Files
upstream-zulip/web/styles/recent_view.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

1073 lines
34 KiB
CSS
Raw Permalink 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.
.recent_view_container {
padding: 0;
overflow: hidden;
display: flex;
flex-direction: column;
position: sticky;
top: var(--navbar-fixed-height);
z-index: 1;
}
.recent_view_container #recent_view_table {
max-width: 100%;
overflow: hidden !important;
display: flex;
flex-direction: column;
border: 0;
background-color: var(--color-background);
}
#recent_view_table .table,
#recent-view-content-table {
/* To keep border properties to the thead th. */
border-collapse: separate;
table-layout: fixed;
border-spacing: 0;
width: 100%;
}
#recent-view-content-table {
border: var(--recent-view-body-border-width) solid
var(--color-border-recent-view-table);
border-top: none;
border-radius: 0 0 5px 5px;
overflow: hidden;
}
#recent_view {
--recent-view-header-channel-column-adjustment: calc(
var(--recent-view-row-left-padding) +
var(--recent-view-body-border-width) -
var(--recent-view-header-border-width)
);
display: none;
padding-top: var(--navbar-fixed-height);
/* Add bottom padding equal to `#bottom-whitespace`. This helps us keep #compose visible
at its max-height without overlapping with any visible topics. */
padding-bottom: var(--max-unmaximized-compose-height);
& td {
box-sizing: border-box;
vertical-align: middle;
padding: 0.1875em 0.5em; /* 3px 8px at 16px/1em */
}
/* Suppress focus rings and the focus-driven vdots reveal when
focus was set programmatically (e.g., on page load or
sidebar click). The class is removed on the first keyboard
navigation, restoring :focus outlines and the icon reveals
below. See focus_outline_util.ts. The icon-opacity rules
mirror the selectors they override (in `.recent_view_focusable`
below) so each wins on specificity from the extra class. */
&.no-visible-focus-outlines .recent_view_focusable {
&:focus {
outline: 0;
}
&:focus
> .change_visibility_policy
:is(
.recent-view-row-topic-menu,
.visibility-status-icon[data-vdots-original-icon-class]
) {
opacity: 0;
}
&.recent-view-body-row:focus:not(:hover)
.change_visibility_policy
:is(
.recent-view-row-topic-menu,
.visibility-status-icon[data-vdots-original-icon-class]
) {
opacity: 0;
}
}
.recent_view_focusable {
& > .zulip-icon {
outline: 0;
}
&:focus {
outline: var(--focus-ring-outline);
/* Match both the natively-rendered vdots icon and the
swapped vdots (signaled by the data attribute set in
`recent_view_ui.update_visibility_icon_swap_state`) so
the wrapper-focus tier reads the same regardless of
whether the row has a status marker. */
> .change_visibility_policy
:is(
.recent-view-row-topic-menu,
.visibility-status-icon[data-vdots-original-icon-class]
) {
/* Wrapper focus = direct interaction on the
menu button; top of the tier. */
opacity: 0.7;
}
}
/* Stickiness: while the 3-dots topic menu has its popover
open, keep the icon in the direct-interaction tier (0.7)
so the user can see which row the open menu belongs to. */
&.topic-popover-visible
> .change_visibility_policy
.visibility-status-icon {
opacity: 0.7;
}
/* Row keyboard-selected but not mouse-hovered: extra-quiet
reveal of the default-state 3-dots icon, so keyboard
navigation doesn't loudly advertise an action the user
rarely needs. Mouse hover's 0.4 rule below overrides
whenever the mouse is on the row. */
&.recent-view-body-row:focus:not(:hover)
.change_visibility_policy
:is(
.recent-view-row-topic-menu,
.visibility-status-icon[data-vdots-original-icon-class]
) {
opacity: 0.2;
}
&.recent-view-topic-visibility {
/* 3px (vs. 5px on `.recent-view-body-row`) keeps a
consistent perceived corner-rounding ratio: 5px on
a wide row reads as a subtle round, but on a small
22×22 ring (icon-natural wrapper + 3px outset) it
reads as nearly circular. */
border-radius: 0.1875em; /* 3px at 16px/1em */
/* 3px rather than 5px: the wrapper sits hard against
the recent-view table's right edge (the table has
overflow:hidden), so a 5px outset left the outline's
right side clipped. 3px gives comfortable clearance
while still matching the inbox's 22×22 effective
ring size around a 16×16 icon. */
outline-offset: 0.1875em; /* 3px at 16px/1em */
}
> .change_visibility_policy {
display: flex;
}
> .change_visibility_policy .recent-view-row-topic-menu {
/* Tertiary action: hidden at rest, revealed on row
hover / focus, brightened on direct interaction. */
opacity: 0;
cursor: pointer;
&:hover {
opacity: 0.7;
}
&:not(.visibility-status-icon) {
display: none;
}
}
}
& a {
color: var(--color-recent-view-link);
text-decoration: none;
}
.empty-table-message {
background-color: var(--color-background);
padding: 3em 1em;
}
.recent-view-empty-load-more {
margin-top: 10px;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
/* Reset the 1.5em font-size inherited from
.empty-table-message so the load-more text
and button match normal UI text size. */
font-size: var(--base-font-size-px);
}
.fa-check-square-o,
.fa-square-o {
width: 0.7142em; /* Legacy 10px size at 14px/1em. */
padding-right: 0.3571em; /* Legacy 5px size at 14px/1em. */
padding-left: 0.1428em; /* Legacy 2px size at 14px/1em. */
}
.table_fix_head {
padding: 0 !important;
border: var(--recent-view-header-border-width) solid
var(--color-border-recent-view-table);
border-radius: 5px 5px 0 0;
overflow: hidden;
}
.recent-view-load-more-container {
margin: 20px 10px;
align-items: center;
}
.fetch-messages-button {
display: grid;
place-items: center;
/* Stack the loading indicator and button label in the
same grid cell so the label stays vertically centered
when the indicator is empty/hidden. */
> * {
grid-row: 1;
grid-column: 1;
}
/* Override the inline height: 0 set by loading.make_indicator
so the spinner participates in grid alignment. */
.loading-indicator {
height: auto !important;
}
.loading_indicator_spinner {
height: 20px;
width: 20px;
}
path {
fill: var(--color-recent-view-loading-spinner);
}
}
#recent_view_filter_buttons {
/* This padding-top value aligns the recents filters
with the filters in the left and right sidebars.
TODO: As part of the recents redesign, these filters
should match the height of the sidebar filters. */
padding: 10px 0 0;
display: flex;
gap: var(--recent-topics-filters-gap);
/* Search box has no height without this in safari. */
flex: 0 0 auto;
flex-wrap: wrap;
justify-content: flex-start;
background: var(--color-background);
}
#recent_filters_group {
display: flex;
flex-flow: row wrap;
gap: var(--recent-topics-filters-gap);
}
#recent-view-search-wrapper {
flex-grow: 1;
margin-bottom: var(--recent-topics-filters-gap);
/* Prevent the search input outline from being clipped
by the overflow:hidden ancestor at fractional browser
zoom levels. Applied on both sides because this
element can wrap to its own line at narrow widths.
2px because 1px can round to 0 device pixels at
certain fractional zoom levels (e.g., 80%). */
margin-inline: 2px;
}
.button-recent-filters {
color: var(--color-text-default);
background-color: var(--color-background-zulip-button);
border: 1px solid var(--color-border-zulip-button);
border-radius: 40px;
/* Matching to the height of the filter search box. */
height: var(--recent-topics-filters-height);
/* Legacy 12px at 14px/1em. */
padding: 0 0.8571em;
flex: 0 0 auto;
display: flex;
align-items: center;
font-family: inherit;
font-size: inherit;
&:hover {
background-color: var(--color-background-zulip-button-hover);
}
&:active {
background-color: var(--color-background-zulip-button-active);
}
&:focus-visible {
background-color: var(
--color-background-recent-filters-button-focus
);
outline: 0;
}
&.fake_disabled_button {
cursor: not-allowed;
opacity: 0.5;
&:hover {
background-color: var(
--color-background-recent-filters-button-disabled
);
border-color: var(
--color-border-recent-filters-button-disabled
);
}
}
}
.button-recent-selected {
color: var(--color-text-brand-subtle-action-button);
background-color: var(--color-background-brand-subtle-action-button);
&:hover {
background-color: var(
--color-background-brand-subtle-action-button-hover
);
}
&:active {
background-color: var(
--color-background-brand-subtle-action-button-active
);
}
}
.unread_count {
/* Focus underline can only occupy the total length of the unread count */
margin-right: 1px;
margin-left: 1px;
align-self: center;
opacity: 1;
outline: 0 solid var(--color-background-unread-counter);
&:hover {
outline-width: var(--focus-ring-width-in-views);
}
}
.unread_mention_info:not(:empty) {
/* Zero out right margin from left sidebar presentation. */
margin-right: 0;
/* Match with its font-size. */
line-height: 14px;
/* Present a default/arrow cursor */
cursor: default;
}
.unread_hidden {
display: none;
}
.flex_container {
display: flex;
align-items: center;
}
.inline-flex-container {
display: inline-flex;
align-items: center;
}
.recent_topic_actions {
/* Add spacing between mention marker, unread count
and mute icon */
margin-left: 0.3125em; /* 5px at 16px/1em */
display: flex;
flex-flow: row nowrap;
}
.recent-view-unread-mention-and-count-wrapper .recent_topic_actions {
/* Unset margin; gap on the wrapper handles spacing. */
margin-left: 0;
margin-right: 0;
}
.recent-view-unread-mention-and-count-wrapper .unread_count {
/* Unset margin; gap on the wrapper handles spacing. */
margin: 0;
}
.mention_in_unread {
opacity: 0.7;
}
.recent_topic_actions.dummy_action_button {
visibility: hidden;
}
.recent_topic_actions .recipient_bar_icon {
/* Zero out padding used in recipient bar. */
padding-right: 0;
padding-left: 0;
}
/* Topic state markers (follow/mute/unmute) are secondary
information: visible at a glance, but quieter than primary
content. Overrides `.recipient_bar_icon`'s 0.2 idle / 0.4
hover from message_header.css. */
.recent_topic_actions
.visibility-status-icon:not(.recent-view-row-topic-menu) {
/* 0.45 is the lowest opacity that meets WCAG 1.4.11's 3:1
non-text contrast against both light and dark row
backgrounds. */
opacity: 0.45;
&:hover {
/* Beat `.recipient_bar_icon:hover`'s !important. */
opacity: 0.7 !important;
}
}
.recent_view_participants {
display: inline-flex; /* Causes LI items to display in row. */
/* Keep avatars centered on the line. */
vertical-align: middle;
list-style-type: none;
margin: auto; /* Centers vertically / horizontally in flex container. */
/* 24px at 16px/1em */
height: 1.5em;
/* 4px at 16px/1em */
padding: 0.25em 0;
border-radius: 6px;
overflow: hidden;
/*
By using the row-reverse layout, the visual ordering will be opposite of
the DOM ordering. This will allows us to stack the items in the opposite
direction of the natural stacking order without having to mess with the
zIndex value. The MAJOR DOWNSIDE is that the HTML itself now reads
backwards, which super janky.
*/
flex-direction: row-reverse;
&:first-child {
/* Remove padding of first child to align with header text. */
padding-left: 0;
}
}
.recent_view_participant_item {
/* 24px at 16px/1em */
height: 1.5em;
margin: 0;
padding: 0 var(--recent-view-participant-item-padding-x);
position: relative;
width: var(--recent-view-participant-item-width);
cursor: pointer;
/* Can't use last-child due to tippy element being appended */
&:last-of-type {
/* Remove right padding of last item to align with header text. */
padding-left: 0;
}
&:first-of-type {
padding-right: 0;
}
.fa-user {
opacity: 0.7;
}
}
.recent_view_participant_avatar,
.recent_view_participant_overflow {
border: 0;
/* Keep the rounded corners from ballooning
to a circle at smaller font sizes.
6px at 16px/1em */
border-radius: 0.375em;
color: var(--color-recent-view-participant-overflow-text);
display: block;
height: 100%;
text-align: center;
background-color: var(
--color-background-recent-view-participant-overflow
);
}
.recent_view_participant_avatar {
background-color: transparent;
}
.recent_view_participant_overflow {
/* 24px at 16px/1em */
line-height: 1.5;
background-color: transparent;
color: var(--color-text-recent-view-last-msg-time);
text-align: left;
}
& tr {
background-color: var(--color-background-recent-view-row);
/* Avoid annoying, confusing hover-state when scrolling on
touch devices like iPad that treat a tap-and-hold/swipe
as a hover. */
@media (hover: hover) and (pointer: fine) {
&:hover {
background-color: var(--color-background-recent-view-row-hover);
.change_visibility_policy .recent-view-row-topic-menu {
/* Tertiary action reveal tier (row hover). */
opacity: 0.45;
}
}
}
}
& tr .recent_topic_name {
/* Extra left padding to make room for the unread marker bar
alongside the keyboard selection outline, applied to all
rows so content aligns between read and unread rows. */
padding-left: var(--recent-view-row-left-padding);
}
.unread_topic {
& a {
color: var(--color-recent-view-link-unread);
font-weight: 500;
}
.recent_topic_name {
position: relative;
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 2px;
height: 100%;
background: linear-gradient(
90deg,
var(--color-unread-marker) 30%,
hsl(217deg 64% 59% / 0%)
);
border-radius: 2px 0 0 2px;
}
}
}
/* When consecutive rows are both unread, make the blue
marker bar continuous with no gap between them. */
.unread_topic + .unread_topic .recent_topic_name::before {
border-top-left-radius: 0;
}
/* Also remove the bottom radius on the preceding unread
row when followed by another unread row. We use
:has() to look ahead at the next sibling. */
.unread_topic:has(+ .unread_topic) .recent_topic_name::before {
border-bottom-left-radius: 0;
}
/* Hide the unread marker bar when the "Unread" filter is active,
since every visible row is already unread. */
&.recent-view-filtered-by-unread .unread_topic .recent_topic_name::before {
display: none;
}
.last_msg_time {
float: left;
margin-right: 5px;
.last-msg-link {
/* Prevent time strings from collapsing over multiple lines. */
display: block;
min-width: max-content;
color: var(--color-text-recent-view-last-msg-time);
}
}
.unread_topic .last-msg-link {
color: var(--color-text-recent-view-last-msg-time-unread);
}
& thead th {
box-sizing: border-box;
text-align: left;
padding: 0.25em 0 0.25em 0.5em; /* 4px at 16px/1em */
background-color: var(--color-background-recent-view-table-thead-th);
overflow: hidden;
color: var(--color-text-recent-view-table-thead-th);
text-transform: uppercase;
font-weight: 600;
line-height: 1.25em; /* 20px at 16px/1em */
z-index: 1;
.recent-view-header-wrapper {
display: flex;
align-items: center;
}
.table-sortable-arrow {
align-self: center;
font-size: 1em; /* 16px at 16px/1em */
transform: rotate(180deg);
opacity: 0;
transition: opacity 100ms ease-out;
color: var(--color-arrow-recent-view-table-thead-th);
}
&.descend .table-sortable-arrow {
transform: rotate(0deg);
}
&:not(.active)[data-sort]:hover .table-sortable-arrow {
opacity: 0.7;
}
&.active .table-sortable-arrow {
opacity: 1;
}
&.active {
opacity: 1;
transition: opacity 100ms ease-out;
}
&[data-sort]:hover {
cursor: pointer;
background-color: var(
--color-background-recent-view-table-thead-sort-header
);
transition: background-color 100ms ease-in-out;
}
.zulip-icon-chevron-right {
font-size: 0.9375em; /* 15px at 16px/1em */
align-self: center;
color: hsl(0deg 0% 60%);
padding: 0 0.125em; /* 2px at 16px/1em */
}
}
#recent-view-table-headers:hover
.recent-view-unread-sort-header
.table-sortable-arrow {
opacity: 0.7;
}
.recent-view-topic-header {
/* Match left padding with row td (.recent_topic_name),
including the extra space for the unread marker bar. */
padding: 0 0.5em 0 0; /* 8px 12px at 16px/1em */
/* th no longer has data-sort; the individual sort spans handle
cursor and hover. */
cursor: default;
.recent-view-header-wrapper {
/* Match the row grid so "Channel" and "Conversation" sort
spans align with channel and topic text in rows. Sort
arrows are inside the spans, so 3 columns suffice.
1em = 16px at 16px/1em, matching the 1em (16px
at 16px/1em) privacy icon width in data rows.
The first column is floored to the "Channel" header's
JS-measured width so the label never overlaps the next
column when channel names are short or absent. */
display: grid;
grid-template-columns:
max(
var(--recent-view-header-channel-column-min-width, 0px),
calc(
min(
calc(
var(
--longest-subscribed-channel-name-width
) +
1em + 8px
),
calc(
calc(
100% -
var(
--recent-view-header-channel-column-adjustment
)
) /
3
)
) +
var(--recent-view-header-channel-column-adjustment)
)
)
auto 1fr auto;
align-items: stretch;
}
.recent-view-channel-sort-header,
.recent-view-conversation-sort-header,
.recent-view-unread-sort-header {
display: flex;
align-items: center;
gap: 4px;
cursor: pointer;
/* Padding gives the hover pill its size. */
padding: 0.25em; /* 4px at 16px/1em */
border-radius: 3px;
transition: background-color 100ms ease-in-out;
&:hover {
background-color: var(
--color-background-recent-view-table-thead-sort-header
);
.table-sortable-arrow {
opacity: 0.7;
}
}
&.active .table-sortable-arrow {
opacity: 1;
}
&.descend .table-sortable-arrow {
transform: rotate(0deg);
}
}
.recent-view-channel-sort-header {
padding-left: 1em;
}
.recent-view-conversation-sort-header {
/* Cancel the pill padding so the label aligns with topic
text in rows. */
margin-left: -0.25em; /* -4px at 16px/1em */
/* Prevent hover pill highlight from extending into
the adjacent unread sort column. */
margin-right: 0.3125em; /* 5px at 16px/1em */
}
.recent-view-unread-sort-header {
/* Use width that reasonably covers 2-3 magnitudes of count. */
width: 1.5em;
margin-right: -0.1563em; /* 2.5px at 16px/1em */
justify-self: end;
justify-content: center;
}
}
.recent_topic_users,
.recent-view-participants-header {
padding-right: 0;
padding-left: var(--recent-view-participants-padding-x-start);
width: calc(
var(--recent-view-participants-padding-x-start) +
(var(--recent-view-max-avatars) + 1) *
(
var(--recent-view-participant-item-width) + 2 *
var(--recent-view-participant-item-padding-x)
) -
/* First item start padding is --recent-view-participants-padding-x-start.
Last item doesn't have end padding. */
2 * var(--recent-view-participant-item-padding-x)
);
}
&.recent-view-participants-hidden {
--recent-view-row-left-padding: 0.5em; /* 8px at 16px/1em */
td {
/* 6px 8px at 16px/1em */
padding: 0.375em 0.5em 0.375em var(--recent-view-row-left-padding);
}
.recent_topic_users,
.recent-view-participants-header {
display: none;
}
}
.recent-view-participants-header .recent-view-header-wrapper {
display: block;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.recent_topic_timestamp,
.recent-view-last-msg-time-header {
/* Time text width is measured from JS and set as
--recent-view-time-text-width. Add the visibility
icon width (1em), cell padding (2 × 0.5em), and space
for the icon's focus outline (0.5em). Falls back to
25% before JS has set the variable. */
width: 25%;
width: calc(var(--recent-view-time-text-width) + 2.5em);
}
.recent_topic_name {
.recent-view-conversation-with-unread-wrapper {
display: grid;
grid-template-areas:
"conversation-type chevron-right conversation-name unread-mention-and-count"
". . conversation-name .";
width: 100%;
/* We add 1em for the privacy icon and 8px for the flexbox
gap between the icon and the channel name. Floored to
match the header grid's "Channel" floor. */
grid-template-columns:
max(
calc(
var(
--recent-view-header-channel-column-min-width,
0px
) -
var(--recent-view-header-channel-column-adjustment)
),
min(
calc(
var(--longest-subscribed-channel-name-width) + 1em +
8px
),
calc(100% / 3)
)
)
auto 1fr auto;
align-items: center;
}
.recent-view-conversation-type-wrapper {
grid-area: conversation-type;
display: flex;
align-items: center;
gap: 8px;
.stream-privacy {
display: flex;
}
}
.recent-view-conversation-link {
grid-area: conversation-name;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.recent-view-unread-mention-and-count-wrapper {
grid-area: unread-mention-and-count;
/* Reserve space so a focused unread badge's `-5px`
outset focus ring (`.recent-view-table-unread-count`'s
`::before`) does not paint over the topic-name's
ellipsis when the topic is long enough to truncate. */
padding-left: 0.4375em; /* 7px at 16px/1em */
}
.zulip-icon-chevron-right {
grid-area: chevron-right;
font-size: 0.9375em; /* 15px at 16px/1em */
color: hsl(0deg 0% 60%);
padding: 0 0.125em; /* 2px at 16px/1em */
}
.recent-view-dm-name,
.recent-view-channel-name {
opacity: 0.8;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
& thead .last_msg_time_header {
/* The responsive table of bootstrap
somehow ignores the width of ::after
element. This ensures it is always visible.
20px = space occupied by ::after (icon) +
some extra padding.
*/
padding-right: 20px;
}
@media (width < $md_min) {
/* Hide last message time on smaller screens. */
&.recent-view-participants-hidden {
.recent_topic_timestamp,
thead .last_msg_time_header {
display: none;
}
}
.recent_topic_actions {
margin-right: 5px;
font-size: 1.0714em; /* 15px at 14px / em */
}
}
.private_conversation_row {
.pm_status_icon {
display: flex;
justify-content: center;
align-items: center;
.zulip-icon.conversation-partners-icon,
.zulip-icon.zulip-icon-bot {
opacity: 0.6;
}
.user-circle {
min-width: var(
--length-user-status-circle-recent-conversations
);
font-size: 0.625em; /* 10px at 16px/1em */
float: left;
position: unset;
/* Make the width 16px to match other icons. */
padding: 0 0.3em; /* 3px at 10/1em */
}
}
.recent-view-dm-group {
/* We don't display status emoji in group DMs,
so prepare an ordinary inline layout... */
.user-status-microlayout {
display: inline;
white-space: nowrap;
}
/* ...and hide the status emoji. */
.status-emoji {
display: none;
}
}
}
}
#recent_view_bottom_whitespace {
#recent_view_loading_messages_indicator,
.bottom-messages-logo {
display: block;
position: absolute;
top: 200px;
left: 0;
right: 0;
margin: auto;
.loading_indicator_spinner {
position: relative;
top: -7px;
}
}
}
#recent_view_folder_filter_container {
display: flex;
align-items: center;
height: var(--recent-topics-filters-height);
}
#recent_view_folder_filter_button {
font-size: 1.5625em; /* 25px at 16px/1em */
padding: 0;
&:focus-visible {
outline: var(--focus-ring-outline);
}
}
#recent-view-filter_widget {
display: inline-flex;
width: 10.7142em; /* 150px at 14px em */
/* Prevent the outline from being clipped by the
overflow:hidden ancestor at fractional browser
zoom levels. 2px because 1px can round to 0
device pixels at certain zoom levels (e.g., 80%). */
margin-left: 2px;
/* 1.5px 6px at 16px/1em */
padding: 0 0.375em;
/* Matching to the height of the filter search box. */
height: var(--recent-topics-filters-height);
/* Matching to the input styles otherwise defined on
.input-element in inputs.css */
color: var(--color-text-input);
background: var(--color-background-input);
border: none;
outline: 1px solid var(--color-outline-input);
outline-offset: -1px;
&:hover {
outline-color: var(--color-outline-input-hover);
}
&:focus {
background-color: var(--color-background-input-focus);
outline-color: var(--color-outline-input-focus);
box-shadow: 0 0 5px var(--color-box-shadow-input-focus);
}
}
#recent_view .recent_topic_timestamp .flex_container {
/* Push the visibility icon to the right edge of the cell. */
justify-content: space-between;
}
.recent-view-unread-mention-and-count-wrapper {
display: flex;
align-items: center;
/* Stretch to the full row height so the unread count
is a larger click target for "Mark as read". */
align-self: stretch;
margin-left: auto;
flex-direction: row;
/* Match the left sidebar gap between @ marker and unread count. */
gap: 5px;
.unread_mention_info {
/* Unset margin in favor of flex gap. */
margin: 0;
}
.recent-view-unread-count-wrapper {
display: flex;
align-items: center;
align-self: stretch;
}
}
.recent-view-body-row {
outline-offset: -0.25em; /* -4px at 16px/1em */
/* 0.4688em (vs. inbox's 0.3125em / 5px) — the larger
negative offset on this view shrinks the ring's effective
corner radius (`border-radius` minus `|outline-offset|`),
so we bump the base radius so the ring's painted corners
read with the same curvature as `.inbox-row`'s 3.5px
effective radius. Em-based so both offset and radius
scale together with the user's font size, keeping the
perceived corner-rounding ratio stable. */
border-radius: 0.4688em; /* 7.5px at 16px/1em */
}
.recent-view-table-unread-count {
border-radius: 0.3125em; /* 5px at 16px/1em */
position: relative;
}
/* Focus ring drawn as a pseudo-element so the ring's corner
radius can be set independently of the badge's, and so the
wrapper-level `:focus` outline rule on `.recent_view_focusable`
(which the badge also matches) does not stack a second concentric
outline on top. Scoped via `#recent_view:not(.no-visible-focus-outlines)`
so it stays suppressed alongside the wrapper outline until the
first keyboard navigation key removes the class (see
focus_outline_util.ts), and so the rule has high enough
specificity to beat the wrapper rule. Inset `-5px` matches the
breathing room the inbox wrapper-extending outline gets from its
`padding: 0 5px`. */
#recent_view:not(.no-visible-focus-outlines)
.recent-view-table-unread-count:focus {
outline: none;
&::before {
content: "";
position: absolute;
inset: -0.3125em; /* -5px at 16px/1em */
border: var(--focus-ring-outline);
border-radius: var(--unread-count-focus-outline-radius-in-views);
pointer-events: none;
}
}