Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
:root {
--tabstrip-inner-border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
--tab-group-suggestions-loading-animation-color-1: color-mix(in srgb, currentColor 5%, transparent);
--tab-group-suggestions-loading-animation-color-2: color-mix(in srgb, currentColor 35%, transparent);
--tab-min-height: 32px;
/* Size and padding shared by the close and audio buttons in .tab-content.
The padding keeps their 12px icons in a 12px content box. Pinned and
collapsed tabs show .tab-icon-overlay instead, sized separately. */
--tab-content-button-size: 20px;
--tab-content-button-padding: 4px;
&[uidensity="compact"] {
--tab-min-height: 28px;
--tab-padding-inline: 6px;
--tab-group-line-toolbar-border-distance: 0px;
--tab-collapsed-split-pill-offset: 2px;
}
--tab-group-label-size: var(--tab-min-height);
&[uidensity="touch"] {
--tab-min-height: 41px;
--tab-group-label-size: var(--tab-min-height);
}
@media (-moz-native-theme) {
--tab-box-shadow-selected: var(--box-shadow-level-1);
}
@media not -moz-pref("browser.nova.enabled") {
--tab-min-height: 36px;
--tab-group-label-size: 24px;
--tab-box-shadow-selected: var(--box-shadow-level-1);
--tab-content-button-size: 24px;
--tab-content-button-padding: var(--tab-close-button-padding);
&[uidensity="compact"] {
--tab-min-height: 29px;
}
&[uidensity="touch"] {
--tab-group-label-size: 27px;
}
}
--tab-group-label-container-size: var(--tab-group-label-size);
--tab-group-counter-size: 24px;
--split-view-padding-block: 2px;
--split-view-tab-padding-inline: 2px;
--tabstrip-min-height: calc(var(--tab-min-height) + 2 * var(--tab-margin-block));
--tab-group-label-height: max(1.5em, var(--tab-min-height) - 14px);
--tab-group-label-padding: 4px;
--tab-group-label-highlight-thickness: 3px;
--tab-group-label-animation-duration: 150ms;
--tab-group-line-thickness: 2px;
--tab-group-line-toolbar-border-distance: 1px;
/* Collapsed tabs should be square, so set width to match the min height */
--tab-collapsed-background-width: var(--tab-min-height);
--tab-collapsed-width: calc(var(--tab-collapsed-background-width) + 2 * var(--tab-margin-inline-inner));
--tab-collapsed-split-pill-offset: 0px;
--tab-pinned-min-width-expanded: calc(var(--tab-background-width-pinned-expanded) + 2 * var(--tab-margin-inline-pinned-expanded));
--tab-note-icon-end-margin: 4px;
--tab-selected-color-scheme: var(--toolbar-color-scheme);
&[lwt-tab-selected="light"] {
--tab-selected-color-scheme: light;
}
&[lwt-tab-selected="dark"] {
--tab-selected-color-scheme: dark;
}
&[lwtheme] {
--tab-border-color-selected: var(--lwt-tab-line-color, currentColor);
}
--tab-dragover-transition: transform 200ms var(--animation-easing-function);
--tab-dragover-outline-color: var(--focus-outline-color);
--tab-vertical-scrollbar-color: auto;
@media (-moz-platform: macos) {
--tab-vertical-scrollbar-color: color-mix(in srgb, currentColor 26%, transparent) transparent;
}
@media -moz-pref("browser.nova.enabled") {
--tab-group-label-padding: 8px;
&[uidensity="compact"] {
--tab-margin-block: 4px;
}
}
/* Sizing and positioning of the container tab line. */
@media -moz-pref("browser.nova.enabled") {
--tab-context-line-block-offset: 3px;
--tab-context-line-inline-offset: calc(var(--tab-padding-inline) + 2px);
/* We need a different block offset for split-view because there's less
* vertical space available there */
--tab-context-line-split-view-block-offset: 1px;
&[uidensity="compact"] {
--tab-context-line-block-offset: 1px;
--tab-context-line-split-view-block-offset: 0px;
}
@media -moz-pref("sidebar.verticalTabs") {
--tab-context-line-block-offset: 3px;
--tab-context-line-inline-offset: var(--tab-padding-inline);
--tab-context-line-split-view-block-offset: 3px;
&[uidensity="compact"] {
--tab-context-line-inline-offset: calc(var(--tab-padding-inline) + 1px);
--tab-context-line-block-offset: 2px;
--tab-context-line-split-view-block-offset: 1px;
}
}
}
@media not -moz-pref("browser.nova.enabled") {
--tab-group-blue: light-dark(var(--color-blue-70), var(--color-blue-20));
--tab-group-blue-invert: light-dark(var(--color-blue-0), var(--color-blue-70));
--tab-group-blue-pale: var(--color-blue-0);
--tab-group-purple: light-dark(var(--color-purple-70), var(--color-purple-20));
--tab-group-purple-invert: light-dark(var(--color-purple-0), var(--color-purple-70));
--tab-group-purple-pale: var(--color-purple-0);
--tab-group-cyan: light-dark(var(--color-cyan-70), var(--color-cyan-20));
--tab-group-cyan-invert: light-dark(var(--color-cyan-0), var(--color-cyan-70));
--tab-group-cyan-pale: var(--color-cyan-0);
--tab-group-orange: light-dark(var(--color-orange-70), var(--color-orange-20));
--tab-group-orange-invert: light-dark(var(--color-orange-0), var(--color-orange-70));
--tab-group-orange-pale: var(--color-orange-0);
--tab-group-yellow: light-dark(var(--color-yellow-70), var(--color-yellow-20));
--tab-group-yellow-invert: light-dark(var(--color-yellow-0), var(--color-yellow-70));
--tab-group-yellow-pale: var(--color-yellow-0);
--tab-group-pink: light-dark(var(--color-pink-70), var(--color-pink-20));
--tab-group-pink-invert: light-dark(var(--color-pink-0), var(--color-pink-70));
--tab-group-pink-pale: var(--color-pink-0);
--tab-group-green: light-dark(var(--color-green-70), var(--color-green-20));
--tab-group-green-invert: light-dark(var(--color-green-0), var(--color-green-70));
--tab-group-green-pale: var(--color-green-0);
--tab-group-red: light-dark(var(--color-red-70), var(--color-red-20));
--tab-group-red-invert: light-dark(var(--color-red-0), var(--color-red-70));
--tab-group-red-pale: var(--color-red-0);
--tab-group-gray: light-dark(#5e6a77, #99a6b4);
--tab-group-gray-invert: light-dark(#f2f9ff, #5e6a77);
--tab-group-gray-pale: #f2f9ff;
}
--tab-group-label-text-dark: var(--color-gray-100);
/* 5px of padding-block are adding to .tabbrowser-tab */
--tab-height-with-margin-padding: calc(5px + var(--tab-min-height) + (2 * var(--tab-margin-block)));
@media -moz-pref("sidebar.verticalTabs") {
--tab-min-height: max(32px, calc(var(--tab-label-line-height) * 1em));
--tab-margin-block: var(--tab-margin-block-vertical);
--tab-padding-inline: var(--tab-padding-inline-vertical);
&[uidensity="compact"] {
--tab-margin-inline-inner: 7px;
}
}
/* Hold the collapsed strip at 50px in normal and compact density, so the
* scrollbar has room next to the tab backgrounds instead of being drawn
* over them. Touch density keeps its natural, wider strip. */
@media -moz-pref("browser.nova.enabled") {
/* 32px tab background + 2 * 9px. */
&:not([uidensity="touch"]) {
--tab-margin-inline-inner: 9px;
}
/* 28px tab background + 2 * 11px. */
&[uidensity="compact"] {
--tab-margin-inline-inner: 11px;
}
}
}
#tabbrowser-tabs {
/* Overriding tabbox.css */
border: 0;
/* Use a bigger flex value than the searchbar to prevent it from
* taking all the toolbar space. */
flex: 1000 1000;
&[movingtab-group] {
--tab-dragover-outline-color: var(--dragover-tab-group-color);
}
&[orient="horizontal"] {
min-height: var(--tabstrip-min-height);
--tab-min-width: 76px;
--tab-min-width-extra-icons: 0px;
--tab-min-width-uidensity: 0px;
--tab-max-width: 225px;
/* Touch mode needs additional space for the close button. */
:root[uidensity="touch"] & {
--tab-min-width-uidensity: 10px;
}
/* Make it easier to drag tabs by expanding the drag area downwards. */
&[movingtab] {
padding-bottom: 15px;
margin-bottom: -15px;
}
--tab-width-transition: min-width 100ms ease-out, max-width 100ms ease-out;
}
&[noshadowfortests] {
--tab-box-shadow-selected: none;
}
&[orient="horizontal"] {
--tab-group-label-highlight-radius: 2px;
}
&[orient="vertical"] {
--tab-group-label-highlight-radius: 4px;
@media -moz-pref("browser.nova.enabled") {
/* The hover highlight fills a full tab-height row and the tab group
* label is inset within it. */
--tab-group-label-hover-inset: 2px;
--tab-group-label-container-size: var(--tab-min-height);
--tab-group-label-size: calc(var(--tab-group-label-container-size) - 2 * var(--tab-group-label-hover-inset));
}
}
}
#navigator-toolbox[movingtab] > #nav-bar {
pointer-events: none;
/* Allow dropping a tab on buttons with associated drop actions. */
> #nav-bar-customization-target {
> #personal-bookmarks,
> #home-button,
> #downloads-button,
> #bookmarks-menu-button {
pointer-events: auto;
}
}
}
.closing-tabs-spacer {
pointer-events: none;
#tabbrowser-arrowscrollbox:not(:hover) > #tabbrowser-arrowscrollbox-periphery > & {
transition: width 0.15s ease-out;
}
}
#tabbrowser-arrowscrollbox-periphery {
position: relative;
}
.tabbrowser-tab[dragtarget],
tab-split-view-wrapper[dragtarget] {
/* Margin needs to be at least 4px to not clip multiselect stacking effect */
overflow-clip-margin: 4px;
z-index: 3 !important;
position: absolute !important;
pointer-events: none; /* avoid blocking dragover events on scroll buttons */
&[multiselected]:not([small-stack], [big-stack], [hasactivetab]) {
visibility: hidden;
}
}
.tabbrowser-tab {
--tab-label-mask-size: 1em;
appearance: none;
background-color: transparent;
color: inherit;
color-scheme: unset;
border-radius: 0;
border-width: 0;
margin: 0;
padding: 0 var(--tab-margin-overflow-clip);
align-items: stretch;
/* Needed so that overflowing content overflows towards the end rather than
getting centered. That prevents tab opening animation from looking off at
justify-content: flex-start;
overflow: clip;
/* Needed to avoid clipping the tab-background shadow, which has a 4px blur. */
overflow-clip-margin: var(--tab-margin-overflow-clip);
#tabbrowser-tabs[orient="horizontal"] &:not([pinned]) {
flex: 100 100;
max-width: var(--tab-max-width);
transition: var(--tab-width-transition);
&:not([fadein]) {
max-width: 0.1px;
min-width: 0.1px;
visibility: hidden;
}
&[fadein] {
min-width: calc(var(--tab-min-width-pref, var(--tab-min-width)) + var(--tab-min-width-extra-icons) + var(--tab-min-width-uidensity));
&:is([muted], [soundplaying], [activemedia-blocked]):not([tab-note]) {
--tab-min-width-extra-icons: 24px;
}
&[tab-note]:not([muted], [soundplaying], [activemedia-blocked]) {
--tab-min-width-extra-icons: 20px;
}
&[tab-note]:is([muted], [soundplaying], [activemedia-blocked]) {
--tab-min-width-extra-icons: 44px;
}
}
}
#tabbrowser-tabs[movingtab] & {
position: relative;
@media (prefers-reduced-motion: no-preference) {
:not(tab-group:active) > &[fadein]:not(:active, [multiselected]),
&[multiselected-move-together],
&[tabdrop-samewindow] {
transition: var(--tab-dragover-transition);
}
}
}
&[multiselected-move-together][multiselected] {
z-index: 3;
&[visually-selected] {
z-index: 4;
}
&:not([selected]) {
z-index: 2;
}
}
@media not -moz-pref("sidebar.visibility", "expand-on-hover") {
/* We need these rules to apply at all times when the sidebar.visibility
pref is not set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has not been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
&:is([muted], [soundplaying], [activemedia-blocked]) {
--tab-icon-margin-inline-end: 2px;
}
}
}
.tab-content {
color: var(--tab-text-color);
position: relative;
padding: 0 var(--tab-padding-inline);
&:not([pinned]) {
min-width: 0;
}
.tabbrowser-tab:hover > .tab-stack > &:not([selected], [multiselected]) {
color: var(--tab-text-color-hover);
}
:root:not([uidensity="compact"], [sidebar-expand-on-hover]) &[pinned] {
padding: 0 calc((var(--tab-min-height) - var(--icon-size)) / 2);
}
&:is([selected], [multiselected]) {
color: var(--tab-text-color-selected);
color-scheme: var(--tab-selected-color-scheme);
}
}
@media (prefers-reduced-motion: no-preference) {
.tab-loading-burst {
border-radius: inherit;
position: relative;
overflow: hidden;
&::before {
position: absolute;
content: "";
/* We set the width to be a percentage of the tab's width so that we can use
the `scale` transform to scale it up to the full size of the tab when the
burst occurs. We also need to set the margin-inline-start so that the
center of the burst matches the center of the favicon. */
width: 5%;
height: 100%;
/* Center the burst over the .tab-loading-burst; it's 9px from the edge thanks
to .tab-content, plus 8px more since .tab-loading-burst is 16px wide. */
margin-inline-start: calc(17px - 2.5%);
}
&[pinned]::before {
/* This is like the margin-inline-start rule above, except that icons for
pinned tabs are 12px from the edge. */
margin-inline-start: calc(20px - 2.5%);
}
&[bursting]::before {
background-color: var(--tab-icon-fill-loading);
clip-path: circle(closest-side);
animation: tab-burst-animation 375ms cubic-bezier(0, 0, 0.58, 1);
}
&[bursting][notselectedsinceload]::before {
animation-name: tab-burst-animation-light;
}
}
@keyframes tab-burst-animation {
0% {
opacity: 0.4;
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(40);
}
}
@keyframes tab-burst-animation-light {
0% {
opacity: 0.2;
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(40);
}
}
}
.tab-icon-pending:not([fadein]),
.tab-icon-image:not([fadein]),
.tab-close-button:not([fadein]),
.tab-background:not([fadein]) {
visibility: hidden;
}
.tab-label:not([fadein]),
.tab-throbber:not([fadein]) {
display: none;
}
/* Width/height & margins apply on tab icon stack children */
.tab-throbber,
.tab-icon-pending,
.tab-icon-image,
.tab-sharing-icon-overlay,
.tab-icon-overlay {
height: var(--icon-size);
width: var(--icon-size);
/* apply end margin to tabs which are:
- oriented horizontally and not pinned
- vertical but expanded and not pinned
- expand on hover enabled, vertical but expanded
*/
#tabbrowser-tabs[orient="horizontal"] &:not([pinned]),
:root:not([sidebar-expand-on-hover]) #tabbrowser-tabs[orient="vertical"][expanded] &:not([pinned]) {
margin-inline-end: var(--tab-icon-margin-inline-end);
}
@media -moz-pref("sidebar.visibility", "expand-on-hover") {
/* We need these rules to apply at all times when the sidebar.visibility
pref is set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
#tabbrowser-tabs[orient="vertical"][expanded] & {
margin-inline-end: var(--tab-icon-margin-inline-end);
}
}
}
.tab-throbber {
&:not([busy]) {
display: none;
}
@media (prefers-reduced-motion: reduce) {
background-image: url("chrome://global/skin/icons/loading.svg");
background-position: center;
background-repeat: no-repeat;
-moz-context-properties: fill;
fill: currentColor;
opacity: 0.4;
&[progress] {
opacity: 0.8;
}
}
@media (prefers-reduced-motion: no-preference) {
:root[sessionrestored] & {
&[busy] {
position: relative;
overflow: hidden;
&::before {
content: "";
position: absolute;
background-image: url("chrome://browser/skin/tabbrowser/loading.svg");
background-position: left center;
background-repeat: no-repeat;
width: 480px;
height: 100%;
animation: tab-throbber-animation 1.05s steps(30) infinite;
-moz-context-properties: fill;
fill: currentColor;
opacity: 0.7;
}
&:-moz-locale-dir(rtl)::before {
animation-name: tab-throbber-animation-rtl;
}
}
&[progress]::before {
fill: var(--tab-icon-fill-loading);
opacity: 1;
}
#TabsToolbar[brighttext] &[progress]:not([selected])::before {
fill: #84c1ff;
}
}
}
}
@keyframes tab-throbber-animation {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100%);
}
}
@keyframes tab-throbber-animation-rtl {
0% {
transform: translateX(0);
}
100% {
transform: translateX(100%);
}
}
.tab-icon-pending:is(:not([pendingicon]), [busy], [pinned]) {
display: none;
}
:root {
--tab-sharing-icon-animation: 3s linear tab-sharing-icon-pulse infinite;
}
@keyframes tab-sharing-icon-pulse {
0%,
16.66%,
83.33%,
100% {
opacity: 0;
}
33.33%,
66.66% {
opacity: 1;
}
}
.tab-icon-image {
-moz-context-properties: fill, stroke;
fill: currentColor;
@media -moz-pref("browser.tabs.fadeOutUnloadedTabs") {
&[pending] {
filter: grayscale(100%);
@media (prefers-color-scheme: dark) {
filter: grayscale(100%) invert();
}
opacity: 0.5;
/* Fade the favicon out */
transition-property: filter, opacity;
transition-duration: 1s;
}
&:not([pending]) {
/* When loading the tab, just show the favicon without a transition.
The favicon turns into the "loading" state anyway, so we don't want
to interfere with that. */
transition: none;
}
}
@media -moz-pref("browser.tabs.fadeOutExplicitlyUnloadedTabs") {
&[pending][discarded] {
filter: grayscale(100%);
@media (prefers-color-scheme: dark) {
filter: grayscale(100%) invert();
}
opacity: 0.5;
/* Fade the favicon out */
transition-property: filter, opacity;
transition-duration: 1s;
}
&:not([pending]) {
/* When loading the tab, just show the favicon without a transition.
The favicon turns into the "loading" state anyway, so we don't want
to interfere with that. */
transition: none;
}
}
&:not([src]),
&:-moz-broken {
content: url("chrome://global/skin/icons/defaultFavicon.svg");
}
&[sharing]:not([selected]) {
animation: var(--tab-sharing-icon-animation);
animation-delay: -1.5s;
}
/* Hide the generic favicon only in horizontal mode. In vertical mode, tabs may not
have labels (collapsed state) or we want icons and labels to line up vertically
(expanded state). */
#tabbrowser-tabs[orient="horizontal"] &:not([src], [pinned], [crashed], [sharing], [pictureinpicture]),
&[busy] {
display: none;
}
}
.tab-sharing-icon-overlay,
.tab-icon-overlay,
.tab-note-icon-overlay {
display: none;
}
.tab-sharing-icon-overlay {
position: relative;
-moz-context-properties: fill;
fill: rgb(224, 41, 29);
animation: var(--tab-sharing-icon-animation);
&[sharing="camera"] {
list-style-image: url("chrome://browser/skin/notification-icons/camera.svg");
}
&[sharing="microphone"] {
list-style-image: url("chrome://browser/skin/notification-icons/microphone.svg");
}
&[sharing="screen"] {
list-style-image: url("chrome://browser/skin/notification-icons/screen.svg");
}
&[sharing]:not([selected]) {
display: revert;
}
}
.tab-icon-overlay {
position: relative;
padding: 2px;
top: -7px;
inset-inline-end: -7px;
z-index: 1; /* Overlay tab title */
@media -moz-pref("browser.nova.enabled") {
top: 7px;
&:not([crashed]) {
box-shadow: var(--box-shadow-level-1);
}
}
#tabbrowser-tabs[orient="vertical"] & {
top: 7px;
}
&[crashed] {
list-style-image: url("chrome://browser/skin/tabbrowser/crashed.svg");
}
#tabbrowser-tabs[orient="vertical"]:not([expanded]) &:not([crashed]),
&[pinned]:not([crashed]) {
&[soundplaying] {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-playing-small.svg");
}
&[muted] {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-muted-small.svg");
}
&[activemedia-blocked] {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-blocked-small.svg");
}
&:is([soundplaying], [muted], [activemedia-blocked]) {
/* We want to make this look like the selected tab, but fully opaque. For that,
* we build a stack of `--lwt-accent-color` (guaranteed opaque), then
* `--toolbox-background-color`, then `--tab-background-color-selected`.
*
* We rely on at least one of `--toolbox-background-color` / `--tab-background-color-selected`
* being opaque on the system themes, so even though `--lwt-accent-color` is
* not set there, it ends up working out because we never see it through.
*
* We also apply one extra color on top (--audio-overlay-extra-background)
* for hover / active feedback.
*/
--audio-overlay-extra-background: transparent;
background-color: var(--lwt-accent-color);
-moz-context-properties: fill;
fill: currentColor;
color-scheme: var(--tab-selected-color-scheme);
border-radius: var(--border-radius-circle);
outline: var(--border-width) solid var(--button-border-color);
outline-offset: calc(-1 * var(--border-width));
background-image: image(var(--audio-overlay-extra-background)), image(var(--toolbox-background-color));
color: var(--toolbox-text-color);
&:-moz-window-inactive {
background-image: image(var(--audio-overlay-extra-background)), image(var(--toolbox-background-color-inactive));
color: var(--toolbox-text-color-inactive);
}
&[selected] {
background-image: image(var(--audio-overlay-extra-background)), image(var(--tab-background-color-selected)), image(var(--toolbox-background-color));
color: var(--tab-text-color-selected);
}
&[selected]:-moz-window-inactive {
background-image:
image(var(--audio-overlay-extra-background)), image(var(--tab-background-color-selected)), image(var(--toolbox-background-color-inactive));
}
&:hover {
--audio-overlay-extra-background: var(--button-background-color-ghost-hover);
/* In forced-colors, --audio-overlay-extra-background will be opaque,
* so foreground needs to match that. Same below. */
/* stylelint-disable-next-line max-nesting-depth */
@media (forced-colors) {
color: var(--button-text-color-ghost-hover);
}
/* stylelint-disable-next-line max-nesting-depth */
@media -moz-pref("browser.nova.enabled") {
border-color: var(--button-border-color-hover);
}
}
&:hover:active {
--audio-overlay-extra-background: var(--button-background-color-ghost-active);
/* stylelint-disable-next-line max-nesting-depth */
@media (forced-colors) {
color: var(--button-text-color-ghost-active);
}
/* stylelint-disable-next-line max-nesting-depth */
@media -moz-pref("browser.nova.enabled") {
border-color: var(--button-border-color-active);
}
}
}
}
&[pinned]:is([soundplaying], [muted], [activemedia-blocked]),
&[crashed] {
display: revert;
}
@media -moz-pref("sidebar.visibility", "expand-on-hover") {
/* We need these rules to apply at all times when the sidebar.visibility
pref is set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
#tabbrowser-tabs[orient="vertical"] &:is([soundplaying], [muted], [activemedia-blocked]) {
display: revert;
}
#tabbrowser-tabs[orient="vertical"] &:not([crashed]) {
&[soundplaying] {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-playing-small.svg");
}
&[muted] {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-muted-small.svg");
}
&[activemedia-blocked] {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-blocked-small.svg");
}
&:is([soundplaying], [muted], [activemedia-blocked]) {
/* We want to make this look like the selected tab, but fully opaque. For that,
* we build a stack of `--lwt-accent-color` (guaranteed opaque), then
* `--toolbox-background-color`, then `--tab-background-color-selected`.
*
* We rely on at least one of `--toolbox-background-color` / `--tab-background-color-selected`
* being opaque on the system themes, so even though `--lwt-accent-color` is
* not set there, it ends up working out because we never see it through.
*
* We also apply one extra color on top (--audio-overlay-extra-background)
* for hover / active feedback.
*/
--audio-overlay-extra-background: transparent;
background-color: var(--lwt-accent-color);
background-image: image(var(--audio-overlay-extra-background)), image(var(--toolbox-background-color));
color: var(--tab-text-color-selected);
fill: currentColor;
-moz-context-properties: fill;
color-scheme: var(--tab-selected-color-scheme);
border-radius: var(--border-radius-circle);
outline: var(--border-width) solid var(--button-border-color);
outline-offset: calc(-1 * var(--border-width));
&:-moz-window-inactive {
background-image: image(var(--audio-overlay-extra-background)), image(var(--toolbox-background-color-inactive));
}
&[selected] {
background-image: image(var(--audio-overlay-extra-background)), image(var(--tab-background-color-selected)), image(var(--toolbox-background-color));
}
&[selected]:-moz-window-inactive {
background-image:
image(var(--audio-overlay-extra-background)), image(var(--tab-background-color-selected)), image(var(--toolbox-background-color-inactive));
}
&:hover {
--audio-overlay-extra-background: var(--button-background-color-ghost-hover);
/* In forced-colors, --audio-overlay-extra-background will be opaque,
* so foreground needs to match that. Same below. */
/* stylelint-disable-next-line max-nesting-depth */
@media (forced-colors) {
color: var(--button-text-color-ghost-hover);
}
/* stylelint-disable-next-line max-nesting-depth */
@media -moz-pref("browser.nova.enabled") {
border-color: var(--button-border-color-hover);
}
}
&:hover:active {
--audio-overlay-extra-background: var(--button-background-color-ghost-active);
/* stylelint-disable-next-line max-nesting-depth */
@media (forced-colors) {
color: var(--button-text-color-ghost-active);
}
/* stylelint-disable-next-line max-nesting-depth */
@media -moz-pref("browser.nova.enabled") {
border-color: var(--button-border-color-active);
}
}
}
}
}
@media not -moz-pref("sidebar.visibility", "expand-on-hover") {
/* We need these rules to apply at all times when the sidebar.visibility
pref is not set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has not been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
#tabbrowser-tabs[orient="vertical"]:not([expanded]) &:is([soundplaying], [muted], [activemedia-blocked]) {
display: revert;
}
}
}
/*
* Tab note icon that overlays the favicon for pinned tabs and the collapsed
* vertical tab strip. The horizontal tab strip and expanded vertical tab strip
* get a separate, more spacious treatment using the `.tab-notes-icon` image.
* Note: This is intended to display instead of the `.tab-icon-overlay`. This
* is defined separately from `.tab-icon-overlay` since the tab notes icon has
* fewer features (e.g. no icon interactivity) and
*/
.tab-note-icon-overlay {
position: relative;
padding: 2px;
top: -7px;
inset-inline-end: -7px;
z-index: 1; /* Overlay tab title */
list-style-image: url("chrome://global/skin/icons/tab-notes-12.svg");
background-color: var(--lwt-accent-color);
/* FIXME: What's the point of the image(transparent)? */
background-image: image(transparent), image(var(--toolbox-background-color));
-moz-context-properties: fill;
fill: var(--tab-text-color-selected);
color-scheme: var(--tab-selected-color-scheme);
border-radius: var(--border-radius-circle);
.tabbrowser-tab &:-moz-window-inactive {
background-image: image(transparent), image(var(--toolbox-background-color-inactive));
}
.tabbrowser-tab[selected] & {
background-image: image(transparent), image(var(--tab-background-color-selected)), image(var(--toolbox-background-color));
}
.tabbrowser-tab[selected] &:-moz-window-inactive {
background-image: image(transparent), image(var(--tab-background-color-selected)), image(var(--toolbox-background-color-inactive));
}
#tabbrowser-tabs[orient="vertical"] & {
top: 7px;
}
#tabbrowser-tabs[orient="vertical"]:not([expanded]) .tabbrowser-tab[tab-note]:not([crashed], [soundplaying], [muted], [activemedia-blocked]) &,
.tabbrowser-tab[pinned][tab-note]:not([crashed], [soundplaying], [muted], [activemedia-blocked]) & {
display: revert;
}
@media -moz-pref("sidebar.visibility", "expand-on-hover") {
/* We need these rules to apply at all times when the sidebar.visibility
pref is set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
#tabbrowser-tabs[orient="vertical"] .tabbrowser-tab[tab-note]:not([crashed], [soundplaying], [muted], [activemedia-blocked]) & {
display: revert;
}
}
@media not -moz-pref("sidebar.visibility", "expand-on-hover") {
/* We need these rules to apply at all times when the sidebar.visibility
pref is not set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has not been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
#tabbrowser-tabs[orient="vertical"]:not([expanded]) .tabbrowser-tab[tab-note]:not([crashed], [soundplaying], [muted], [activemedia-blocked]) & {
display: revert;
}
}
}
.tab-audio-button {
display: none;
margin-inline-end: var(--tab-icon-margin-inline-end);
--icon-size: var(--icon-size-xsmall);
--button-size-icon-small: var(--tab-content-button-size);
--button-min-height-small: var(--tab-content-button-size);
--button-border-radius: var(--tab-border-radius);
@media not -moz-pref("browser.nova.enabled") {
--button-border-radius: var(--border-radius-small);
}
@media not -moz-pref("sidebar.visibility", "expand-on-hover") {
/* We need these rules to apply at all times when the sidebar.visibility
pref is not set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has not been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
#tabbrowser-tabs[orient="horizontal"] &:not([pinned]):not([crashed]),
:root:not([sidebar-expand-on-hover]) #tabbrowser-tabs[orient="vertical"][expanded] &:not([pinned]):not([crashed]) {
&:is([soundplaying], [muted], [activemedia-blocked]) {
display: flex;
}
&[soundplaying]::part(button) {
background-image: url("chrome://browser/skin/tabbrowser/tab-audio-playing-small.svg");
}
&[muted]::part(button) {
background-image: url("chrome://browser/skin/tabbrowser/tab-audio-muted-small.svg");
}
&[activemedia-blocked]::part(button) {
background-image: url("chrome://browser/skin/tabbrowser/tab-audio-blocked-circle-12.svg");
}
}
}
}
.tab-label-container {
overflow: hidden;
&[pinned] {
width: 0;
}
&[textoverflow] {
&[labeldirection="ltr"],
&:not([labeldirection]):-moz-locale-dir(ltr) {
direction: ltr;
mask-image: linear-gradient(to left, transparent, black var(--tab-label-mask-size));
}
&[labeldirection="rtl"],
&:not([labeldirection]):-moz-locale-dir(rtl) {
direction: rtl;
mask-image: linear-gradient(to right, transparent, black var(--tab-label-mask-size));
}
}
}
.tab-label {
margin-inline: 0;
line-height: var(--tab-label-line-height); /* override 'normal' in case of fallback math fonts with huge metrics */
white-space: nowrap;
}
.tab-close-button {
-moz-context-properties: fill, fill-opacity;
margin-inline-end: calc(var(--tab-padding-inline) / -2);
width: var(--tab-content-button-size);
height: var(--tab-content-button-size);
box-sizing: border-box;
padding: var(--tab-content-button-padding);
background-color: var(--button-background-color-ghost);
color: var(--button-text-color-ghost);
outline-color: var(--tab-close-button-border-color);
/* Adjust border radius by the distance to the tab. This is a hardcoded approximation
because the exact distance is intentionally not always equal across all sides. */
border-radius: calc(var(--tab-border-radius) - 3px);
&:hover {
color: var(--button-text-color-ghost-hover);
background-color: var(--button-background-color-ghost-hover);
outline-color: var(--tab-close-button-border-color-hover);
}
&:hover:active {
color: var(--button-text-color-ghost-active);
background-color: var(--button-background-color-ghost-active);
outline-color: var(--tab-close-button-border-color-active);
}
#tabbrowser-tabs[orient="horizontal"] &[pinned],
:root:not([sidebar-expand-on-hover]) #tabbrowser-tabs[orient="vertical"] &[pinned],
#tabbrowser-tabs[closebuttons="activetab"][orient="horizontal"] &:not([selected]) {
display: none;
}
}
/* The following rulesets allow showing more of the tab title by shrinking the
* width of the close button. We don't do this in forced-colors mode since
* the button has a visible outline shown */
@media not (forced-colors) {
#tabbrowser-tabs[orient="horizontal"] {
@media not -moz-pref("browser.nova.enabled") {
.tabbrowser-tab:not([labelendaligned], [tab-note], :hover) > .tab-stack > .tab-content > .tab-close-button {
padding-inline-start: 0;
width: 18px;
}
}
.tabbrowser-tab[visuallyselected]:not([labelendaligned]):hover,
&:not([closebuttons="activetab"]) .tabbrowser-tab:not([visuallyselected], [labelendaligned]):hover {
--tab-label-mask-size: 2em;
}
}
}
.tab-background {
/* The label takes its color from the sibling .tab-content. */
/* stylelint-disable-next-line stylelint-plugin-mozilla/use-paired-color-tokens */
background-color: var(--tab-background-color);
border-radius: var(--tab-border-radius);
margin-block: var(--tab-margin-block);
min-height: var(--tab-min-height);
outline: var(--tab-border);
outline-color: var(--tab-border-color);
outline-offset: var(--tab-outline-offset);
.tabbrowser-tab:hover > .tab-stack > &:not([selected], [multiselected]) {
background-color: var(--tab-background-color-hover);
outline-color: var(--tab-border-color-hover);
}
&:is([selected], [multiselected]) {
background-color: var(--tab-background-color-selected);
outline-color: var(--tab-border-color-selected);
box-shadow: var(--tab-box-shadow-selected);
}
@media -moz-pref("browser.nova.enabled") {
border: 1px solid transparent;
background-clip: border-box;
/* The below lines are required for dark, light, and
system themes to achieve the gradient border appearance */
@media not ((prefers-contrast) or (-moz-native-theme)) {
:root[theme-in-app] &:is([selected]:not([multiselected])) {
background:
var(--tab-border-color-accent) border-box border-area,
var(--tab-background-color-selected) padding-box;
}
}
}
&[multiselected] {
outline-color: var(--focus-outline-color);
&[selected] {
outline-width: 2px;
outline-offset: -2px;
}
}
#tabbrowser-tabs[orient="vertical"] & {
.tabbrowser-tab[small-stack] > .tab-stack > & {
box-shadow:
0 5px 0 -3px var(--tab-background-color-selected),
0 3px var(--tab-dragover-outline-color);
}
.tabbrowser-tab[big-stack] > .tab-stack > & {
box-shadow:
0 5px 0 -3px var(--tab-background-color-selected),
0 3px var(--tab-dragover-outline-color),
0 8px 0 -3px var(--tab-background-color-selected),
0 6px var(--tab-dragover-outline-color);
}
}
#tabbrowser-tabs[orient="horizontal"] & {
.tabbrowser-tab[small-stack] > .tab-stack > & {
box-shadow:
5px 0 0 -3px var(--tab-background-color-selected),
3px 0 var(--tab-dragover-outline-color);
}
.tabbrowser-tab[big-stack] > .tab-stack > & {
box-shadow:
5px 0 0 -3px var(--tab-background-color-selected),
3px 0 var(--tab-dragover-outline-color),
8px 0 0 -3px var(--tab-background-color-selected),
6px 0 var(--tab-dragover-outline-color);
}
&:-moz-locale-dir(rtl) {
.tabbrowser-tab[small-stack] > .tab-stack > & {
box-shadow:
-5px 0 0 -3px var(--tab-background-color-selected),
-3px 0 var(--tab-dragover-outline-color);
}
.tabbrowser-tab[big-stack] > .tab-stack > & {
box-shadow:
-5px 0 0 -3px var(--tab-background-color-selected),
-3px 0 var(--tab-dragover-outline-color),
-8px 0 0 -3px var(--tab-background-color-selected),
-6px 0 var(--tab-dragover-outline-color);
}
}
}
#tabbrowser-tabs[movingtab] & {
transition:
background-color 50ms ease,
color 50ms ease,
outline-color 50ms ease;
}
#tabbrowser-tabs[movingtab-group] & {
&[dragover-groupTarget] {
background-color: light-dark(var(--dragover-tab-group-color-pale), var(--dragover-tab-group-color));
color: light-dark(var(--dragover-tab-group-color), var(--dragover-tab-group-color-pale));
outline-color: light-dark(var(--dragover-tab-group-color), var(--dragover-tab-group-color-pale));
@media -moz-pref("browser.nova.enabled") {
background-color: var(--dragover-tab-group-color-invert);
color: currentColor;
outline-color: var(--dragover-tab-group-color);
outline-width: 2px;
}
}
&:is([selected], [multiselected]) {
@media not -moz-pref("browser.nova.enabled") {
outline-color: var(--dragover-tab-group-color);
outline-width: 2px;
outline-offset: -2px;
}
}
}
}
/* Keyboard focus outline */
#TabsToolbar #firefox-view-button:focus-visible > .toolbarbutton-icon,
#tabbrowser-tabs[tablist-has-focus] .tabbrowser-tab.tablist-keyboard-focus > .tab-stack > .tab-background {
outline: var(--focus-outline);
outline-offset: var(--focus-outline-inset);
}
/* Container stroke indicator. Colors come from the --identity-* custom
properties set by the container color classes in usercontext.css. */
@media not -moz-pref("browser.nova.enabled") {
.tabbrowser-tab[usercontextid] > .tab-stack > .tab-background > .tab-context-line {
background-color: var(--identity-icon-color);
height: 2px;
border-radius: var(--border-radius-xsmall);
margin: 0 calc(var(--tab-border-radius) / 2);
position: relative;
#tabbrowser-tabs[orient="vertical"] & {
height: auto;
width: 2px;
margin: calc(var(--tab-border-radius) / 2) 0;
}
}
}
@media -moz-pref("browser.nova.enabled") {
.tabbrowser-tab[usercontextid] > .tab-stack > .tab-background > .tab-context-line {
height: 0;
/* border-block guarantees it's snapped to device pixels */
border-block: 1px solid transparent;
background: var(--identity-stroke-color) border-box border-box;
border-radius: var(--border-radius-xsmall);
margin-block-start: var(--tab-context-line-block-offset);
width: calc(100% - 2 * var(--tab-context-line-inline-offset));
margin-inline-start: var(--tab-context-line-inline-offset);
/* With expand on hover, size of the stroke is always the collapsed size */
:root[sidebar-expand-on-hover] & {
width: calc(var(--tab-collapsed-background-width) - 2 * var(--tab-context-line-inline-offset));
}
}
:is(#tabbrowser-tabs[orient="horizontal"], :root:not([sidebar-expand-on-hover]) #tabbrowser-tabs[orient="vertical"][expanded])
.tabbrowser-tab[usercontextid]:not([visuallyselected], [multiselected], [pinned])
> .tab-stack
> .tab-background
> .tab-context-line {
background-color: transparent;
background-image: linear-gradient(to left, transparent, var(--identity-stroke-color) var(--tab-label-mask-size));
&:-moz-locale-dir(rtl) {
background-image: linear-gradient(to right, transparent, var(--identity-stroke-color) var(--tab-label-mask-size));
}
}
}
/* Pinned tabs */
.tabbrowser-tab:is([image], [pinned]) > .tab-stack > .tab-content[attention]:not([selected]),
.tabbrowser-tab > .tab-stack > .tab-content[pinned][titlechanged]:not([selected]),
#tabbrowser-tabs[orient="vertical"] .tabbrowser-tab > .tab-stack > .tab-content[titlechanged]:not([selected]) {
background-image: radial-gradient(circle, var(--tab-attention-dot-color), var(--tab-attention-dot-color) 2px, transparent 2px);
background-position: center bottom 6.5px;
background-size: 4px 4px;
background-repeat: no-repeat;
#tabbrowser-tabs[orient="vertical"] & {
background-position-y: 6px;
background-position-x: calc(var(--tab-padding-inline) + var(--icon-size) + 1px);
&:-moz-locale-dir(rtl) {
background-position-x: right calc(var(--tab-padding-inline) + var(--icon-size) + 1px);
}
:root:not([sidebar-expand-on-hover]) &[pinned] {
background-position-x: calc(50% + 11px);
&:-moz-locale-dir(rtl) {
background-position-x: calc(50% - 11px);
}
}
}
}
.tabbrowser-tab[image] > .tab-stack > .tab-content[attention]:not([pinned], [selected]) {
background-position-x: left calc(var(--tab-padding-inline) + 6px);
&:-moz-locale-dir(rtl) {
background-position-x: right calc(var(--tab-padding-inline) + 6px);
}
}
.tab-label[attention]:not([selected]) {
font-weight: var(--font-weight-bold);
}
#pinned-tabs-container[orient="horizontal"] {
max-width: max(80px, calc(100vw - var(--window-controls-size) - 300px /* Room for toolbar buttons, drag space, and unpinned tabs */));
&:empty {
display: none;
}
}
#pinned-drop-indicator-icon,
#pinned-drop-indicator-text {
display: none;
}
#pinned-drop-indicator {
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
color: var(--toolbarbutton-icon-fill-attention);
outline: 1px dashed currentColor;
@media not (prefers-reduced-motion) {
transition-duration: 0.25s;
transition-timing-function: ease-in-out;
}
&[visible] {
display: flex;
border-radius: var(--border-radius-small);
background: color-mix(in srgb, currentColor 12%, transparent);
#pinned-drop-indicator-icon {
width: var(--size-item-small);
height: var(--size-item-small);
-moz-context-properties: fill;
fill: currentColor;
display: inline;
}
}
&[interactive] {
outline-style: solid;
}
}
#tabbrowser-tabs[orient="vertical"] > #pinned-drop-indicator {
transition-property: height;
&[visible] {
height: 70px;
width: calc(100% - 2 * var(--tab-margin-inline-inner));
gap: var(--space-small);
margin: var(--space-small) var(--tab-margin-inline-inner) 0;
@starting-style {
height: 0;
}
> #pinned-drop-indicator-text {
display: inline;
text-align: center;
}
#tabbrowser-tabs:not([expanded]) > & {
width: var(--tab-collapsed-background-width);
height: var(--size-item-large);
/* stylelint-disable max-nesting-depth */
> #pinned-drop-indicator-text {
display: none;
}
}
}
}
#tabbrowser-tabs[orient="horizontal"] > #pinned-drop-indicator {
transition-property: min-width;
&[visible] {
margin-inline: var(--space-small);
align-self: center;
align-items: flex-start;
min-width: calc(2 * var(--size-item-large));
height: var(--tab-min-height);
padding-inline-start: var(--space-small);
@starting-style {
min-width: 0;
}
> #pinned-drop-indicator-text {
display: none;
}
}
}
/* Split View */
tab-group > tab-split-view-wrapper {
#tabbrowser-tabs[orient="vertical"] & {
#tabbrowser-tabs[expanded] & {
margin-inline-start: calc(var(--space-medium) + var(--tab-margin-inline-inner) - var(--space-xsmall));
}
#tabbrowser:not([expanded]) & {
margin-inline-start: calc(var(--space-medium) - var(--space-xsmall));
}
#tabbrowser-tabs:not([expanded]) & .tab-group-line {
inset-inline-start: calc((var(--tab-margin-inline-inner) * -1) + 2px) !important;
}
> .tabbrowser-tab {
overflow: visible;
.tab-group-line {
inset-inline-start: calc(var(--tab-margin-inline-inner) * -1) !important;
inset-block-start: calc(var(--space-xsmall) * -2);
inset-block-end: calc(var(--space-xsmall) * -1);
}
&:last-child {
.tab-group-line {
display: none;
@container vertical-tabs-container (max-width: 210px) {
display: flex;
}
}
}
}
}
}
#tabbrowser-tabs[orient="horizontal"] tab-split-view-wrapper {
/* Height value that allows us to match the height of a tab inside vs outside
a split view. */
--split-view-tab-height: calc(var(--tab-min-height) - 2 * var(--split-view-padding-block));
margin-block: var(--tab-margin-block);
margin-inline: 0;
align-items: flex-end;
flex: 100 100;
padding: var(--split-view-padding-block) 0;
min-width: calc(var(--tab-min-width-pref, var(--tab-min-width)) * 2 + 6px);
max-width: var(--tab-max-width);
transition: var(--tab-width-transition);
.tabbrowser-tab {
--split-view-tab-strip-inset: calc(var(--tab-margin-block) + var(--split-view-padding-block));
margin-block: calc(-1 * var(--split-view-tab-strip-inset));
padding-block: var(--split-view-tab-strip-inset);
}
.tab-group-line {
inset-block-end: calc(var(--tab-group-line-toolbar-border-distance) - var(--tab-margin-block) - var(--split-view-padding-block));
/* The line is positioned against the stack, whose padding box includes
--split-view-tab-padding-inline here. */
inset-inline: calc(var(--split-view-tab-padding-inline) - var(--tab-margin-overflow-clip));
@media not -moz-pref("browser.nova.enabled") {
inset-inline-start: calc(var(--space-small) * -2 + var(--split-view-tab-padding-inline));
}
@media -moz-pref("browser.nova.enabled") {
inset-inline-end: calc(-1 * var(--tab-margin-overflow-clip));
}
}
&[last-tab-or-split-view] .tabbrowser-tab:last-child .tab-group-line {
inset-inline-end: calc(var(--tab-border-radius) / 2 + var(--split-view-tab-padding-inline));
@media -moz-pref("browser.nova.enabled") {
inset-inline-end: calc(var(--split-view-tab-padding-inline) - var(--tab-margin-overflow-clip));
}
}
/* Small-ish subtree, but probably should be removed */
/* stylelint-disable-next-line stylelint-plugin-mozilla/no-has-selector */
&:has(tab:is([muted], [soundplaying], [activemedia-blocked])) {
min-width: 200px;
}
tab-group[collapsed] &:not([hasactivetab]) {
min-width: 0 !important;
max-width: 0 !important;
max-height: 0 !important;
padding: 0;
margin: 0;
overflow: hidden;
}
.tabbrowser-tab {
padding-inline: 0;
/* The stack gets the padding and the divider so that the tab's own box
can reach the edge of the tab strip. */
> .tab-stack {
padding-inline: var(--split-view-tab-padding-inline);
}
.tab-background {
min-height: var(--split-view-tab-height);
}
/* With a relatively larger font, the label's line box can be taller than
--split-view-tab-height in compact mode. */
.tab-label-container {
height: var(--split-view-tab-height);
}
tab-group & {
overflow: visible;
}
.tab-content[attention]:not(selected) {
background-position-y: bottom 0.5px !important;
background-position-x: left calc(var(--tab-padding-inline) + var(--icon-size) - 7px) !important;
&:-moz-locale-dir(rtl) {
background-position-x: right calc(var(--tab-padding-inline) + var(--icon-size) - 7px) !important;
}
@media not (-moz-platform: linux) {
background-position-x: left calc(var(--tab-padding-inline) + var(--icon-size) - 10px) !important;
&:-moz-locale-dir(rtl) {
background-position-x: right calc(var(--tab-padding-inline) + var(--icon-size) - 10px) !important;
}
}
}
/* prettier-ignore */
#tabbrowser-tabs[movingtab-addToGroup] tab-split-view-wrapper[dragtarget] & {
overflow: visible;
}
}
}
/* Tabs in split-view-wrapper defaults */
#tabbrowser-tabs tab-split-view-wrapper {
--tab-context-line-block-offset: var(--tab-context-line-split-view-block-offset);
--split-view-wrapper-padding: round(var(--space-xsmall), env(hairline));
display: grid;
grid-template-columns: 1fr 1fr;
margin-inline: var(--space-small);
padding: var(--split-view-wrapper-padding);
border-radius: var(--tab-border-radius);
position: relative; /* prevents splitview wrappers from shifting during other drag events*/
-moz-window-dragging: no-drag;
&[hidden] {
display: none;
}
&[hasactivetab] {
/* The tabs inside the wrapper take their own colors. */
/* stylelint-disable-next-line stylelint-plugin-mozilla/use-paired-color-tokens */
background-color: var(--tab-background-color-hover);
@media (forced-colors) {
border: 1px solid SelectedItem;
background: SelectedItemText;
}
}
@media (prefers-reduced-motion: no-preference) {
#tabbrowser-tabs[movingtab] &:not(:active) {
transition: var(--tab-dragover-transition);
}
}
&[multiselected][small-stack],
&[multiselected][big-stack] {
outline: 1px solid var(--tab-dragover-outline-color);
}
/* show outline when split view wrapper is about to be grouped */
#tabbrowser-tabs[movingtab-group] &[dragover-groupTarget] {
background-color: light-dark(var(--dragover-tab-group-color-pale), var(--dragover-tab-group-color));
color: light-dark(var(--dragover-tab-group-color), var(--dragover-tab-group-color-pale));
outline-color: light-dark(var(--dragover-tab-group-color), var(--dragover-tab-group-color-pale));
@media -moz-pref("browser.nova.enabled") {
background-color: var(--dragover-tab-group-color-invert);
color: currentColor;
outline-color: var(--dragover-tab-group-color);
outline-width: 2px;
}
}
.tabbrowser-tab {
:root[uidensity="compact"] & {
--tab-collapsed-background-width: 24px;
}
.tab-background {
margin-inline: 0;
margin-block: 0;
}
.tab-content {
padding-inline: var(--space-medium);
background-position-y: 4px !important;
background-position-x: left calc(var(--tab-padding-inline) + var(--icon-size) - 7px) !important;
&:-moz-locale-dir(rtl) {
background-position-x: right calc(var(--tab-padding-inline) + var(--icon-size) - 7px) !important;
}
@media (forced-colors) {
#tabbrowser-tabs tab-split-view-wrapper[hasactivetab] .tabbrowser-tab:not([selected]) & {
color: SelectedItem;
}
}
}
/* Two-column split only: first/last tab adjustments. Same pattern for horizontal
tab strips and for vertical expanded, with different @container names and the
same 211px min-width. */
#tabbrowser-tabs[orient="horizontal"] tab-split-view-wrapper & {
&:first-child {
@container vertical-tabs-container (min-width: 211px) {
tab-split-view-wrapper:not([hasactivetab]) & {
border-block-end: transparent;
}
}
}
&:last-child {
@container tab-split-view-horizontal (min-width: 211px) {
.tab-content {
padding-inline-start: var(--space-medium);
}
}
}
}
:root:not([sidebar-expand-on-hover]) #tabbrowser-tabs[orient="vertical"][expanded] tab-split-view-wrapper & {
&:first-child {
tab-split-view-wrapper:not([hasactivetab]) & {
border-block-end: transparent;
}
}
&:last-child {
@container vertical-tabs-container (min-width: 211px) {
.tab-content {
padding-inline-start: var(--space-medium);
}
}
}
}
:root:not([sidebar-expand-on-hover]) #tabbrowser-tabs[orient="vertical"][expanded] tab-split-view-wrapper & {
&:first-child {
tab-split-view-wrapper:not([hasactivetab]) & {
border-block-end: transparent;
}
}
}
:root:not([sidebar-expand-on-hover]) #tabbrowser-tabs[orient="vertical"][expanded] tab-split-view-wrapper & {
&:first-child {
tab-split-view-wrapper:not([hasactivetab]) & {
border-block-end: transparent;
}
}
}
}
&:not([hasactivetab]) {
outline: var(--tab-border);
outline-offset: var(--tab-outline-offset);
&:hover {
background-color: var(--tab-background-color-hover);
outline-color: var(--tab-border-color-hover);
}
.tabbrowser-tab {
&:not([multiselected]) {
.tab-background {
outline-color: transparent;
}
&:hover .tab-background {
background-color: transparent;
outline-color: transparent;
}
}
}
}
.tabbrowser-tab:last-child > .tab-stack {
border-inline-start: 1px solid transparent;
}
&:not([hasactivetab]) .tabbrowser-tab:last-child > .tab-stack {
border-inline-start-color: var(--toolbarbutton-icon-fill);
}
}
/* Overrides for split-view-wrapped tabs in a vertical tabstrip */
#tabbrowser-tabs[orient="vertical"] tab-split-view-wrapper {
--split-view-wrapper-inline-inset: calc(var(--tab-padding-inline) - var(--space-medium));
--split-view-tab-strip-inset: round(var(--split-view-wrapper-inline-inset), env(hairline));
border-radius: var(--tab-border-radius);
gap: var(--space-xsmall);
grid-template-columns: 1fr;
/* Derive the margin from the snapped total inset and padding, so that the
* difference remains device pixel aligned. */
margin-inline: calc(var(--split-view-tab-strip-inset) - var(--split-view-wrapper-padding));
.tabbrowser-tab {
margin-inline: calc(-1 * var(--split-view-tab-strip-inset));
padding-inline: var(--split-view-tab-strip-inset);
/* Beats the vertical tab strip's padding-block rules, including the
:nth-child(1 of ...) one. */
padding-block: 0 !important;
}
}
/* Side by side, each tab only borders the tab strip on its own side. */
:root:not([sidebar-expand-on-hover]) #tabbrowser-tabs[orient="vertical"][expanded] tab-split-view-wrapper {
@container vertical-tabs-container (min-width: 211px) {
.tabbrowser-tab:first-child {
margin-inline-end: 0;
padding-inline-end: 0;
}
.tabbrowser-tab:last-child {
margin-inline-start: 0;
padding-inline-start: 0;
}
}
}
#tabbrowser-tabs[orient="vertical"][expanded] tab-split-view-wrapper {
grid-template-columns: 1fr 1fr;
@container vertical-tabs-container (max-width: 210px) {
grid-template-columns: 1fr;
@media -moz-pref("browser.nova.enabled") {
border-radius: var(--border-radius-large);
}
&:not([hasactivetab]) .tabbrowser-tab {
&:first-child > .tab-stack {
border-block-end: 1px solid var(--toolbarbutton-icon-fill);
border-inline-end: transparent;
}
}
.tabbrowser-tab:last-child > .tab-stack {
border-inline-start: none !important;
}
}
}
/* When expand-on-hover is enabled, always stack split-view tabs in a single column */
:root[sidebar-expand-on-hover] #tabbrowser-tabs[orient="vertical"][expanded] tab-split-view-wrapper {
grid-template-columns: 1fr;
@media -moz-pref("browser.nova.enabled") {
border-radius: var(--border-radius-large);
}
&:not([hasactivetab]) .tabbrowser-tab {
&:first-child > .tab-stack {
border-block-end: 1px solid var(--toolbarbutton-icon-fill);
border-inline-end: transparent;
}
&:last-child > .tab-stack {
border-inline-start: transparent !important;
}
}
}
/* When expand-on-hover is enabled, always stack split-view tabs in a single column */
:root[sidebar-expand-on-hover] #tabbrowser-tabs[orient="vertical"][expanded] tab-split-view-wrapper {
grid-template-columns: 1fr;
&:not([hasactivetab]) .tabbrowser-tab {
&:first-child > .tab-stack {
border-block-end: 1px solid var(--toolbarbutton-icon-fill);
border-inline-end: transparent;
}
&:last-child > .tab-stack {
border-inline-start: transparent !important;
}
}
}
/* Overrides for split-view-wrapped tabs in a collapsed vertical tabstrip */
#tabbrowser-tabs[orient="vertical"]:not([expanded]) tab-split-view-wrapper {
--split-view-wrapper-inline-inset: calc(var(--tab-margin-inline-inner) + var(--tab-collapsed-split-pill-offset));
/* When the user begins to drag a collapsed sidebar, the wrapper should not stretch. */
align-self: start;
/* Prevent the close button from being cutoff by the bookmarks toolbar / nav bar
if split view is first in list if non-pinned vertical tabs */
&:first-child {
margin-block-start: var(--space-xsmall);
}
&:not([hasactivetab]) .tabbrowser-tab:first-child > .tab-stack {
border-block-end: 1px solid var(--toolbarbutton-icon-fill);
border-inline-end: transparent;
}
.tabbrowser-tab:last-child > .tab-stack {
border-inline-start-width: 0;
}
/* Allow close button to overflow the split view wrapper */
.tabbrowser-tab {
overflow: visible;
.tab-content {
padding-inline: unset;
width: var(--tab-collapsed-background-width);
justify-content: center;
background-position-y: 4px !important;
background-position-x: left calc(var(--tab-padding-inline) + var(--icon-size) - 10px) !important;
&:-moz-locale-dir(rtl) {
background-position-x: right calc(var(--tab-padding-inline) + var(--icon-size) - 10px) !important;
}
@media not (-moz-platform: linux) {
background-position-x: left calc(var(--tab-padding-inline) + var(--icon-size) - 7px) !important;
&:-moz-locale-dir(rtl) {
background-position-x: right calc(var(--tab-padding-inline) + var(--icon-size) - 7px) !important;
}
}
}
}
.tab-close-button {
top: -5px;
inset-inline-start: -7px;
}
}
/* During expand-on-hover collapse animation, keep split-tab icons
constrained to the collapsed pill geometry to avoid mid-transition drifting. */
:root[sidebar-expand-on-hover]
#tabbrowser-tabbox[sidebar-ongoing-animations]
#tabbrowser-tabs[orient="vertical"]
tab-split-view-wrapper
.tabbrowser-tab
.tab-content {
width: var(--tab-collapsed-background-width);
justify-content: center;
}
/* Drag/drop of split-view-wrapped tabs */
#tabbrowser-tabs[orient="vertical"] tab-split-view-wrapper {
&[small-stack] {
box-shadow:
0 5px 0 -3px var(--tab-background-color-selected),
0 3px var(--tab-dragover-outline-color);
}
:root[sidebar-expand-on-hover] &:first-child {
margin-block-start: var(--space-xsmall);
}
&[big-stack] {
box-shadow:
0 6px 0 -3px var(--tab-background-color-selected),
0 4px var(--tab-dragover-outline-color),
0 9px 0 -3px var(--tab-background-color-selected),
0 7px var(--tab-dragover-outline-color);
}
}
#tabbrowser-tabs[orient="horizontal"] tab-split-view-wrapper {
&[small-stack] {
box-shadow:
5px 0 0 -3px var(--tab-background-color-selected),
3px 0 0 1px var(--tab-dragover-outline-color);
}
&[big-stack] {
box-shadow:
5px 0 0 -3px var(--tab-background-color-selected),
3px 0 0 1px var(--tab-dragover-outline-color),
8px 0 0 -3px var(--tab-background-color-selected),
6px 0 0 1px var(--tab-dragover-outline-color);
}
&:-moz-locale-dir(rtl) {
&[small-stack] {
box-shadow:
-5px 0 0 -3px var(--tab-background-color-selected),
-3px 0 0 1px var(--tab-dragover-outline-color);
}
&[big-stack] {
box-shadow:
-5px 0 0 -3px var(--tab-background-color-selected),
-3px 0 0 1px var(--tab-dragover-outline-color),
-8px 0 0 -3px var(--tab-background-color-selected),
-6px 0 0 1px var(--tab-dragover-outline-color);
}
}
}
/* Tab Groups */
/*
* .tab-group-line needs to span the drop shadows + space between tabs in the
* same tab group so that the whole tab group appears to be underlined by an
* unbroken line.
*
* The last tab in a tab group should have its group underline stop
* at the end edge of the tab itself, otherwise it looks like the tab group
* extends too far past the edge of the tab.
*
* When a tab group with the currently selected tab is collapsed, the selected
* tab remains visible along with its underline. If there are other tabs in
* the group that have been hidden by the collapse, a counter indicating the
* number of hidden tabs appears at the end of the group, which continues
* the underline, so in this case the line should not terminate underneath
* the tab.
*
*/
.tab-group-line {
display: none;
position: absolute;
background-color: var(--tab-group-line-color);
/* prettier-ignore */
#tabbrowser-tabs:is([movingtab-ungroup], [movingtab-group]) tab-split-view-wrapper[dragtarget] & {
display: none;
}
/* prettier-ignore */
#tabbrowser-tabs[orient="vertical"]:is([movingtab-ungroup], [movingtab-group]) tab-split-view-wrapper[dragtarget] .tabbrowser-tab:first-child & {
display: flex;
}
/* prettier-ignore */
#tabbrowser-tabs[movingtab][movingtab-addToGroup]:not([movingtab-group], [movingtab-ungroup]) tab-split-view-wrapper[dragtarget] & {
display: flex;
background-color: var(--dragover-tab-group-color);
}
/* prettier-ignore */
#tabbrowser-tabs[orient="vertical"][movingtab][movingtab-addToGroup]:not([expanded]) tab-split-view-wrapper[dragtarget] & {
inset-inline-start: calc((var(--tab-margin-inline-inner) * -1) + 2px) !important;
}
/* prettier-ignore */
#tabbrowser-tabs[orient="vertical"][movingtab]:is([expanded]) tab-split-view-wrapper[dragtarget] .tabbrowser-tab:last-child & {
display: none;
}
#tabbrowser-tabs[orient="horizontal"] & {
height: var(--tab-group-line-thickness);
inset-inline: calc(-1 * var(--tab-margin-overflow-clip));
inset-block-end: var(--tab-group-line-toolbar-border-distance);
tab-group:not([collapsed]) > .tabbrowser-tab:last-of-type > .tab-stack > .tab-background > &,
tab-group[collapsed]:not([hasmultipletabs]) & {
inset-inline-end: calc(var(--tab-border-radius) / 2);
border-start-end-radius: calc(var(--tab-group-line-thickness) / 2);
border-end-end-radius: calc(var(--tab-group-line-thickness) / 2);
@media -moz-pref("browser.nova.enabled") {
inset-inline-end: calc(-1 * var(--tab-margin-overflow-clip));
}
}
}
#tabbrowser-tabs[orient="vertical"] & {
width: var(--tab-group-line-thickness);
inset-block: -3px -2px;
inset-inline: 2px 0;
#tabbrowser-tabs[expanded] & {
inset-inline-start: 0;
}
tab-group:not([collapsed]) > .tabbrowser-tab:last-of-type > .tab-stack > .tab-background > &,
tab-group[collapsed]:not([hasmultipletabs]) & {
inset-block-end: 0;
border-end-start-radius: calc(var(--tab-group-line-thickness) / 2);
border-end-end-radius: calc(var(--tab-group-line-thickness) / 2);
}
}
tab-group & {
display: flex;
}
/* prettier-ignore */
#tabbrowser-tabs:is([movingtab-ungroup], [movingtab-group]) tab-group > tab-split-view-wrapper:active .tabbrowser-tab > .tab-stack > .tab-background > & {
display: none;
}
/* prettier-ignore */
#tabbrowser-tabs[movingtab]:not([movingtab-group],[movingtab-ungroup]) .tabbrowser-tab:is(:active,[multiselected]) > .tab-stack > .tab-background > & {
display: flex;
background-color: var(--dragover-tab-group-color);
border-radius: var(--border-radius-xsmall);
}
#tabbrowser-tabs:is([movingtab-group], [movingtab-ungroup]) &:is([selected], [multiselected]) {
display: none;
}
}
tab-group {
/*
* Let the tab bar flexbox distribute space between all tabs evenly, regardless of
* whether they are children of the tab bar directly or children of tab groups
*/
display: contents;
--tab-group-line-color: var(--tab-group-color);
@media -moz-pref("browser.nova.enabled") {
--tab-group-line-color: var(--tab-group-background-color);
}
#tabbrowser-tabs[orient="horizontal"] &[movingtabgroup][collapsed] > .tabbrowser-tab[visuallyselected],
#tabbrowser-tabs[orient="horizontal"] &[collapsed] > .tabbrowser-tab:not([visuallyselected], [multiselected]) {
min-width: 0 !important;
max-width: 0 !important;
padding: 0;
overflow-clip-margin: 0;
}
#tabbrowser-tabs[orient="horizontal"] &[movingtabgroup][collapsed] > tab-split-view-wrapper[hasactivetab],
#tabbrowser-tabs[orient="vertical"] &[movingtabgroup][collapsed] > .tabbrowser-tab[visuallyselected],
#tabbrowser-tabs[orient="vertical"] &[movingtabgroup][collapsed] > tab-split-view-wrapper[hasactivetab],
#tabbrowser-tabs[orient="vertical"] &[collapsed] > .tabbrowser-tab:not([visuallyselected], [multiselected]),
#tabbrowser-tabs[orient="vertical"] &[collapsed] > tab-split-view-wrapper:not([hasactivetab]) {
display: none;
}
&[collapsed] {
@media not -moz-pref("browser.nova.enabled") {
--tab-group-line-color: light-dark(var(--tab-group-color), var(--tab-group-color-pale));
}
/* Override xul.css, we're using the collapsed attribute for our own purposes */
visibility: inherit;
}
}
#tabbrowser-tabs[orient="vertical"][expanded] {
tab-group > :is(.tab-group-label-container, .tabbrowser-tab),
&[movingtab][movingtab-addToGroup]:not([movingtab-group], [movingtab-ungroup]) .tabbrowser-tab:is(:active, [multiselected]) {
margin-inline-start: var(--space-medium);
}
&[movingtab][movingtab-addToGroup]:not([movingtab-group], [movingtab-ungroup]) tab-split-view-wrapper > .tabbrowser-tab:is(:active, [multiselected]) {
margin-inline-start: unset;
}
}
/**
* Tab group label and overflow counter should appear to be underlined
* with the same continuous line as the group's tabs. This is achieved
* by positioning pseudoelement of the appropriate size and color.
*/
.tab-group-label-container,
.tab-group-overflow-count-container {
position: relative;
#tabbrowser-tabs:is([orient="horizontal"], [orient="vertical"]:not([expanded])) tab-group:not([collapsed]) > &::after,
#tabbrowser-tabs:is([orient="horizontal"], [orient="vertical"]:not([expanded])) tab-group[hasactivetab] > &::after,
#tabbrowser-tabs[orient="vertical"] tab-group[hasactivetab][hasmultipletabs] > &.tab-group-overflow-count-container::after {
content: "";
background-color: var(--tab-group-line-color);
position: absolute;
}
#tabbrowser-tabs[orient="vertical"][expanded] & {
contain: inline-size;
}
}
.tab-group-label-container {
&[dragtarget] {
z-index: 3;
position: absolute;
pointer-events: none; /* avoid blocking dragover events on scroll buttons */
}
@media (prefers-reduced-motion: no-preference) {
#tabbrowser-tabs[movingtab] &:not(:active) {
transition: var(--tab-dragover-transition);
}
}
/*
* Provide some empty space to either side of the tab group label.
* Use margin at the start because the group line should not extend beyond
* the tab group label.
* Use padding at the end because the group line should extend to connect to
* the group line of the first tab in the group.
*/
#tabbrowser-tabs[orient="horizontal"] & {
margin-inline-start: 3px;
padding-inline-end: 3px;
}
#tabbrowser-tabs[orient="vertical"] & {
margin-block-start: var(--space-small);
tab-group:not([collapsed]) > &,
tab-group[collapsed][hasactivetab] > & {
padding-block-end: var(--space-small);
}
@media -moz-pref("browser.nova.enabled") {
margin-block-start: calc(var(--tab-margin-block) + var(--tab-padding-block-start));
tab-group[collapsed]:not([hasactivetab]) > & {
margin-block-end: calc(var(--tab-margin-block) + var(--tab-padding-block-end));
}
}
}
#tabbrowser-tabs[orient="horizontal"] tab-group:not([collapsed]) > &::after,
#tabbrowser-tabs[orient="horizontal"] tab-group[collapsed][hasactivetab]:not([movingtabgroup]) > &::after {
height: var(--tab-group-line-thickness);
inset: auto 0 var(--tab-group-line-toolbar-border-distance);
border-start-start-radius: 1px;
border-end-start-radius: 1px;
}
#tabbrowser-tabs[orient="vertical"] tab-group:not([collapsed]) > &::after,
#tabbrowser-tabs[orient="vertical"] tab-group[collapsed][hasactivetab]:not([movingtabgroup]) > &::after {
width: var(--tab-group-line-thickness);
inset-block: 0;
inset-inline: 2px auto;
border-start-start-radius: 1px;
border-start-end-radius: 1px;
}
}
.tab-group-overflow-count-container {
display: none;
#tabbrowser-tabs:not([movingtab]) tab-group[collapsed][hasmultipletabs][hasactivetab] > & {
display: flex;
}
/*
* Similar to .tab-group-label, use padding/margin to space the indicator
* correctly relative to the group line.
*/
#tabbrowser-tabs[orient="horizontal"] & {
padding-inline-end: 3px;
margin-inline-end: 3px;
@media -moz-pref("browser.nova.enabled") {
padding-inline-start: var(--space-xsmall);
}
}
#tabbrowser-tabs[orient="vertical"] & {
#tabbrowser-tabs[expanded] & {
margin-inline-start: var(--space-medium);
}
tab-group:not([collapsed]) > & {
margin-block-end: var(--space-small);
}
}
#tabbrowser-tabs[orient="horizontal"] tab-group[hasactivetab][hasmultipletabs] > &::after {
height: var(--tab-group-line-thickness);
inset: auto 0 var(--tab-group-line-toolbar-border-distance);
border-start-end-radius: 1px;
border-end-end-radius: 1px;
}
#tabbrowser-tabs[orient="vertical"] tab-group[hasactivetab][hasmultipletabs] > &::after {
width: var(--tab-group-line-thickness);
inset-block: 0;
border-end-start-radius: 1px;
border-end-end-radius: 1px;
}
#tabbrowser-tabs:not([expanded]) &::after {
inset-inline: 2px auto;
}
}
.tab-group-overflow-count {
color: var(--tab-group-line-color);
margin: 0;
padding: var(--space-small);
#tabbrowser-tabs[orient="vertical"] & {
margin-inline-start: var(--tab-margin-inline-inner);
width: var(--tab-group-counter-size);
}
#tabbrowser-tabs[orient="vertical"]:not([expanded]) & {
margin-inline-start: calc(var(--tab-margin-inline-inner) + (var(--tab-min-height) - var(--tab-group-counter-size)) / 2);
}
@media -moz-pref("browser.nova.enabled") {
text-align: center;
color: var(--tab-group-background-color);
padding: var(--space-xsmall);
background-color: color-mix(in srgb, var(--tab-group-background-color) 10%, transparent);
height: var(--tab-group-counter-size);
min-width: var(--tab-group-counter-size);
border-radius: var(--border-radius-circle);
text-overflow: ellipsis;
white-space: nowrap;
line-height: calc(var(--tab-group-counter-size) - 2 * var(--space-xsmall));
}
}
.tab-group-label-hover-highlight {
tab-group[collapsed] & {
/* Since effective border radius is the sum of border-radius and box-shadow
* spread radius, make sure that these values vary together in order to add
* up to --tab-border-radius.
*/
@media not -moz-pref("browser.nova.enabled") {
border-radius: calc(var(--tab-border-radius) - var(--tab-group-label-highlight-radius));
#tabbrowser-tabs[orient="horizontal"] & {
padding-block: 4px;
}
}
}
#tabbrowser-tabs[orient="vertical"][expanded] & {
margin-inline-end: var(--space-medium);
}
/* Echo the shape of .tab-group-label, including its sharper bottom start
* corner.
*/
@media -moz-pref("browser.nova.enabled") {
#tabbrowser-tabs[orient="vertical"] & {
block-size: var(--tab-group-label-container-size);
padding-inline: var(--tab-group-label-hover-inset);
border-radius: calc(var(--tab-group-label-container-size) / 2);
border-end-start-radius: calc(var(--tab-group-label-size) / 8 + var(--tab-group-label-hover-inset));
}
}
#tabbrowser-tabs[orient="vertical"]:not([expanded]) & {
/*
* Keep tab group label square in collapsed sidebar centered without
* margin: auto, similar to how tabs' .tab-background use margin in order
* to stay centered in the collapsed sidebar. This helps prevent the tab
* group label from jumping around during the sidebar collapsed-to-expanded
* transition.
*/
margin-inline: calc(var(--tab-margin-inline-inner) + (var(--tab-collapsed-background-width) - var(--tab-group-label-size)) / 2);
@media -moz-pref("browser.nova.enabled") {
margin-inline: var(--tab-margin-inline-inner);
}
}
tab-group[collapsed]:not([movingtabgroup]) &:hover,
tab-group[previewpanelactive] & {
@media not -moz-pref("browser.nova.enabled") {
background-color: var(--tab-background-color-hover);
box-shadow: 0 0 0 var(--tab-group-label-highlight-radius) var(--tab-background-color-hover);
}
@media -moz-pref("browser.nova.enabled") {
#tabbrowser-tabs[orient="vertical"][expanded] & {
background-color: var(--tab-background-color-hover);
}
.tab-group-label {
background-color: var(--tab-group-background-color-hover);
}
}
}
}
.tab-group-label {
-moz-window-dragging: no-drag;
text-align: center;
font-weight: var(--font-weight-semibold);
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
text-shadow: none;
/* .tab-group-label-hover-highlight shadow surrounds the .tab-group-label; keep
* the border radius of the inside element 2px smaller so that these two elements
* look good when hovering over a collapsed tab group label.
*/
border-radius: calc(var(--tab-border-radius) - 2px);
line-height: calc(var(--tab-group-label-height) - var(--tab-group-line-thickness));
min-height: var(--tab-group-label-height);
min-width: var(--tab-group-label-height);
max-width: 10em;
padding-inline: var(--tab-group-label-padding);
color: light-dark(var(--tab-group-color-pale), var(--tab-group-label-text-dark));
background-color: var(--tab-group-color);
margin: auto 0;
@media -moz-pref("browser.nova.enabled") {
line-height: var(--tab-group-label-size);
min-width: var(--tab-group-label-size);
color: var(--tab-group-text-color);
background-color: var(--tab-group-background-color);
border-radius: calc(var(--tab-group-label-size) / 2);
border-end-start-radius: calc(var(--tab-group-label-size) / 8);
&:hover {
background-color: var(--tab-group-background-color-hover);
}
}
/* Animations for hovering a tab(s) over a collapsed tab group. Indicates to
* the user that they can drop the tab(s) into the tab group.
*/
transition: box-shadow var(--tab-group-label-animation-duration);
&[dragover-groupTarget] {
box-shadow: color-mix(in oklab, var(--tab-group-color) 30%, transparent) 0 0 0 var(--tab-group-label-highlight-thickness);
@media -moz-pref("browser.nova.enabled") {
box-shadow: none;
}
}
tab-group[collapsed] > .tab-group-label-container & {
background-color: var(--tab-group-color-invert);
color: light-dark(var(--tab-group-color), var(--tab-group-color-pale));
outline: 1px solid light-dark(var(--tab-group-color), var(--tab-group-color-pale));
outline-offset: -1px;
@media -moz-pref("browser.nova.enabled") {
color: var(--tab-group-text-color);
background-color: var(--tab-group-background-color);
outline: none;
&[dragover-groupTarget] {
box-shadow: none;
color: var(--tab-group-text-color-invert);
background-color: var(--tab-group-color-invert);
outline: 2px solid var(--tab-group-background-color);
}
}
}
#tabbrowser-tabs[tablist-has-focus] &.tablist-keyboard-focus {
outline: var(--focus-outline);
outline-offset: var(--focus-outline-offset);
}
#tabbrowser-tabs[orient="vertical"] & {
height: var(--tab-group-label-size);
min-height: auto;
line-height: var(--tab-group-label-size);
min-width: var(--tab-group-label-size);
#tabbrowser-tabs:not([expanded]) & {
width: var(--tab-group-label-size);
max-width: var(--tab-group-label-size);
font-size-adjust: 0;
&::first-letter {
font: message-box;
font-weight: var(--font-weight-semibold);
line-height: var(--tab-group-label-size);
}
}
}
#tabbrowser-tabs[expanded] & {
align-self: start;
max-width: -moz-available;
}
}
.tab-group-editor-panel {
--panel-width: 22em;
--panel-padding: 0;
font: menu;
@media -moz-pref("browser.nova.enabled") {
--panel-padding: var(--space-large) var(--space-small) 0;
--input-text-background-color: var(--background-color-box);
--panel-separator-padding: 0;
--panel-menuitem-padding-block: var(--space-xsmall);
--panel-width: 24em;
> .panel-header {
justify-content: start;
text-align: start;
min-height: 0;
padding-block: var(--space-xsmall) var(--space-medium);
}
/* Clip the header in the edit modal for a11y. */
&:not(.tab-group-editor-mode-create) > .panel-header {
position: absolute;
overflow: hidden;
clip-path: inset(50%);
width: 0;
height: 0;
min-height: 0;
pointer-events: none;
}
/* Hide all toolbarseparators except the tab group suggestions one.
toolbarseparator:not(#tab-group-suggestions-separator) {
display: none;
}
/* Clip the name label in the edit modal for a11y. */
&:not(.tab-group-editor-mode-create) > .tab-group-editor-name > label {
position: absolute;
overflow: hidden;
clip-path: inset(50%);
width: 0;
height: 0;
pointer-events: none;
}
.panel-footer {
margin-block-start: var(--space-small);
margin-inline: var(--panel-menuitem-margin-inline);
}
}
&.tab-group-editor-panel-expanded {
--panel-width: 25em;
}
&.tab-group-editor-mode-create .tab-group-edit-mode-only,
&:not(.tab-group-editor-mode-create) .tab-group-create-mode-only {
display: none;
}
.tab-group-editor-name {
display: flex;
flex-direction: column;
margin: var(--panel-menuitem-margin);
@media not -moz-pref("browser.nova.enabled") {
padding-top: var(--panel-menuitem-padding-block);
}
> label {
margin-inline: 0;
margin-bottom: var(--space-small);
}
> input[type="text"] {
padding: var(--space-medium);
}
}
.tab-group-editor-swatches {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
margin: var(--panel-menuitem-margin);
padding-block: var(--panel-menuitem-padding-block);
@media -moz-pref("browser.nova.enabled") {
padding-block: 0 var(--space-large);
}
}
input[name="tab-group-color"] {
width: 0;
height: 0;
opacity: 0;
margin: 0;
position: absolute;
pointer-events: none;
top: -100px;
}
.tab-group-editor-swatch {
font-size: 0;
width: 16px;
height: 16px;
/* stylelint-disable-next-line stylelint-plugin-mozilla/use-design-tokens */
padding: var(--focus-outline-offset);
border: var(--focus-outline-width) solid transparent;
border-radius: var(--border-radius-medium);
background-clip: content-box;
background-color: var(--tabgroup-swatch-color);
@media -moz-pref("browser.nova.enabled") {
width: 20px;
height: 20px;
background-color: var(--tabgroup-swatch-color);
border-radius: var(--border-radius-circle);
}
input:checked + & {
border-color: var(--focus-outline-color);
}
input:disabled + & {
opacity: 0.5;
}
input:focus-visible + & {
outline: 1px solid var(--focus-outline-color);
outline-offset: 1px;
}
}
}
@media not (prefers-contrast) {
#tabGroupEditor_deleteGroup {
color: var(--text-color-error);
}
}
/* Tab Notes */
.tab-note-editor-panel {
--panel-width: 300px;
font: menu;
> .panel-header[hidden] {
display: none;
}
> toolbarseparator {
padding-inline: var(--panel-padding);
}
> .panel-subview-body {
padding-top: var(--panel-subview-body-padding-block);
padding-inline: var(--panel-padding);
}
> .panel-action-row {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--space-large);
}
}
#tab-note-editor-button-delete {
color: var(--icon-color-critical);
}
#tab-note-text {
padding: var(--space-medium);
resize: none;
min-height: 3lh;
max-height: 352px;
overflow-y: auto;
}
#tab-note-overflow-indicator {
font-size: 0.85em;
visibility: hidden;
color: var(--text-color-deemphasized);
/* This will apply to both the overflow=warn state (the user has almost
* overflowed the limit) and the overflow=overflow state (the user actually
* has overflowed the limit).
*/
.tab-note-editor-panel[overflow] & {
visibility: inherit;
}
.tab-note-editor-panel[overflow="overflow"] & {
color: var(--text-color-error);
}
}
/* Tab Overflow */
#tabbrowser-arrowscrollbox,
#pinned-tabs-container {
&[orient="horizontal"] {
&:not([scrolledtostart])::part(overflow-start-indicator),
&:not([scrolledtoend])::part(overflow-end-indicator) {
width: 7px; /* The width is the sum of the inline margins */
/* prettier-ignore */
background-image: radial-gradient(ellipse at bottom,
rgba(0,0,0,0.1) 0%,
rgba(0,0,0,0.1) 7.6%,
rgba(0,0,0,0) 87.5%);
background-repeat: no-repeat;
background-position: -3px;
border-left: 0.5px solid rgba(255, 255, 255, 0.2);
pointer-events: none;
position: relative;
border-bottom: 0.5px solid transparent;
}
&:not([scrolledtostart])::part(overflow-start-indicator) {
margin-inline: -0.5px -6.5px;
}
&:not([scrolledtoend])::part(overflow-end-indicator) {
margin-inline: -6.5px -0.5px;
}
&:-moz-locale-dir(rtl)::part(overflow-start-indicator),
&:-moz-locale-dir(ltr)::part(overflow-end-indicator) {
transform: scaleX(-1);
}
}
&[orient="vertical"] {
&::part(overflow-start-indicator),
&::part(overflow-end-indicator) {
background-image: linear-gradient(to top, transparent 0%, light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05)));
background-repeat: no-repeat;
pointer-events: none;
position: relative;
height: 16px;
z-index: 1;
margin-block: 0 -16px;
@media -moz-pref("browser.nova.enabled") {
background-image: linear-gradient(to top, transparent, var(--toolbox-background-color));
}
}
/* Flip the fade at the bottom */
&::part(overflow-end-indicator) {
transform: scaleY(-1);
margin-block: -16px 0;
}
}
/* Scroll arrows */
&::part(scrollbutton-up),
&::part(scrollbutton-down) {
--arrowscrollbox-scrollicon-border-radius: var(--tab-border-radius);
--arrowscrollbox-scrollicon-hover-background-color: var(--toolbarbutton-background-color-hover);
--arrowscrollbox-scrollicon-active-background-color: var(--toolbarbutton-background-color-active);
--arrowscrollbox-scrollicon-padding: var(--toolbarbutton-padding-inner) 2px;
appearance: none;
padding: 0 4px;
fill: var(--toolbarbutton-icon-fill);
margin: 0;
}
#navigator-toolbox:not(:hover) &:not([highlight])::part(scrollbutton-down) {
--arrowscrollbox-scrollicon-transition: 1s background-color ease-out;
}
&[highlight]::part(scrollbutton-down) {
--arrowscrollbox-scrollicon-background-color: SelectedItem;
}
&[scrolledtostart]::part(overflow-start-indicator),
&[scrolledtoend]::part(overflow-end-indicator) {
opacity: 0;
}
&::part(overflow-start-indicator),
&::part(overflow-end-indicator) {
transition: opacity 150ms ease;
}
}
#tabbrowser-arrowscrollbox[orient="horizontal"]::part(scrollbox) {
contain: inline-size;
}
/* Vertical tabs styling */
#tabbrowser-arrowscrollbox[orient="vertical"] {
/* Don't allow resizing below the height of 3 tabs */
min-height: calc(3 * var(--tab-height-with-margin-padding));
&::part(scrollbutton-up),
&::part(scrollbutton-down) {
display: none;
}
&::part(scrollbox) {
scrollbar-width: thin;
scrollbar-color: var(--tab-vertical-scrollbar-color);
overscroll-behavior-y: contain;
/* A wheel notch, an arrow key and a scrollbar arrow button move rows. */
-moz-line-scroll-amount: var(--tab-height-with-margin-padding);
}
> #tabbrowser-arrowscrollbox-periphery {
/* Since tabs-newtab-button is inside tabbrowser-arrowscrollbox, hiding it when the tab strip overflows
* collapses the periphery to 0px height. That can put the tab strip back under the overflow threshold,
* thus showing the button again and oscillating between tabs-newtab-button and vertical-tabs-newtab-button.
* Set a small enough minimum height to stop the periphery from collapsing while keeping the content off the
* overflow threshold. */
min-height: 2px;
}
}
#tabbrowser-arrowscrollbox[orient="vertical"] > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button,
#vertical-tabs-newtab-button {
appearance: none;
min-height: var(--tab-min-height);
line-height: var(--tab-label-line-height);
border-radius: var(--tab-border-radius);
padding: 0 calc(var(--tab-padding-inline) - var(--tab-margin-inline-inner));
width: var(--tab-collapsed-background-width);
margin-inline: var(--tab-margin-inline-inner);
position: relative;
/* Extend the click target across the inline margins (Fitts's law) */
&::before {
content: "";
position: absolute;
block-size: 100%;
inset-inline: calc(-1 * var(--tab-margin-inline-inner));
}
#tabbrowser-tabs[orient="vertical"]:not([expanded]) & > .toolbarbutton-text {
display: none;
}
&:hover {
background-color: var(--tab-background-color-hover);
outline-color: var(--tab-border-color-hover);
&:active {
color: var(--button-text-color-ghost-active);
background-color: var(--button-background-color-ghost-active);
}
}
&:focus-visible {
outline: var(--focus-outline);
outline-offset: var(--focus-outline-inset);
}
> .toolbarbutton-text {
text-align: start;
padding-inline-start: var(--tab-icon-margin-inline-end);
color: var(--toolbarbutton-icon-fill);
}
}
/* For #vertical-tabs-newtab-button, shown when tabs are overflowing, the gap
* with the other items comes from the grid-gap on tabbrowser-tabs which is a
* flex container. #tabs-newtab-button is a child of the arrowscrollbox where
* we don't want a gap (between tabs), so we have to add some margin.
*/
#tabbrowser-arrowscrollbox[orient="vertical"] > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button {
margin-block: var(--tab-margin-block);
}
#tabbrowser-tabs[expanded] {
> #vertical-tabs-newtab-button {
width: auto;
}
> #tabbrowser-arrowscrollbox[orient="vertical"] > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button {
width: 100%;
}
}
#vertical-tabs {
overflow: hidden;
display: none;
&[visible] {
display: flex;
flex-grow: 1;
container-type: inline-size;
container-name: vertical-tabs-container;
}
}
#pinned-tabs-container[orient="vertical"] {
--tab-pinned-min-width: var(--tab-collapsed-width);
/* Don't allow resizing below the height of 1 row of pinned tabs */
min-height: var(--tab-height-with-margin-padding);
&:empty {
display: none;
}
&::part(scrollbutton-up),
&::part(scrollbutton-down) {
display: none;
}
&::part(scrollbox) {
scrollbar-width: thin;
scrollbar-color: var(--tab-vertical-scrollbar-color);
overscroll-behavior-y: contain;
/* A wheel notch, an arrow key and a scrollbar arrow button move rows. */
-moz-line-scroll-amount: var(--tab-height-with-margin-padding);
}
.tabbrowser-tab:not(:hover) > .tab-stack > .tab-background:not([selected], [multiselected]) {
background-color: color-mix(in srgb, currentColor 7%, transparent);
}
&::part(items-wrapper) {
flex: 0 1 0;
}
:root:not([sidebar-expand-on-hover]) & {
--tab-padding-inline: calc((var(--tab-collapsed-background-width) + 2 * var(--tab-margin-inline-pinned-expanded) - var(--icon-size)) / 2);
@media not -moz-pref("sidebar.visibility", "expand-on-hover") {
/* We need these rules to apply at all times when the sidebar.visibility
pref is not set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has not been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
&::part(items-wrapper) {
grid-template-columns: repeat(auto-fit, minmax(var(--tab-pinned-min-width), auto));
display: grid;
grid-auto-rows: var(--tab-height-with-margin-padding);
}
.tab-label-container {
display: none;
}
}
.tab-content {
justify-content: center;
}
#tabbrowser-tabs {
display: grid;
}
#tabbrowser-tabs[expanded] > & {
--tab-pinned-min-width: var(--tab-pinned-min-width-expanded);
.tab-background {
margin-inline: var(--tab-margin-inline-pinned-expanded);
}
&::part(items-wrapper) {
padding-inline: var(--tab-container-margin-inline-pinned-expanded);
}
}
}
@media -moz-pref("sidebar.visibility", "expand-on-hover") {
/* We need this rule to apply at all times when the sidebar.visibility
pref is set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
grid-template-columns: 1fr;
}
}
#vertical-pinned-tabs-splitter {
display: block;
border: none;
background-color: transparent;
background-image: var(--sidebar-divider-image);
background-size: var(--sidebar-divider-size);
background-position: var(--sidebar-divider-position);
background-repeat: no-repeat;
margin-inline: var(--tab-margin-inline-inner);
min-height: 2px;
@media -moz-pref("browser.nova.enabled") {
min-height: 4px;
}
#pinned-tabs-container:empty + & {
display: none;
}
@media not -moz-pref("sidebar.verticalTabs") {
display: none;
}
&:hover {
background-color: var(--focus-outline-color);
background-image: none;
border-radius: var(--border-radius-medium);
}
#tabbrowser-tabs[expanded] > & {
background-image: none;
/* Expand on hover keeps the full width line, with the hover state on top. */
@media -moz-pref("sidebar.visibility", "expand-on-hover") {
&:not(:hover) {
border-top: var(--tabstrip-inner-border);
}
}
}
/* Collapsing holds the launcher at its expanded width so that clip-path has
something to clip, so the divider would otherwise be drawn around the width
it is animating away from. Wait for the real width to be restored. */
#sidebar-container[sidebar-ongoing-animations] #tabbrowser-tabs:not([expanded]) > & {
background-image: none;
}
}
#tabbrowser-tabs[orient="vertical"] {
--tab-min-width: unset;
--tab-padding-inline: calc((var(--tab-collapsed-width) - var(--icon-size)) / 2);
/* Space between a tab and the tabs above and below it, outside of
* --tab-margin-block. Anything else that occupies a row in the tab strip
* (i.e. a tab group label) needs to reserve the same space in order to
* preserve spacing rhythm.
*/
--tab-padding-block-start: 3px;
--tab-padding-block-end: 2px;
min-height: 0;
display: flex;
flex-direction: column;
align-content: flex-start;
grid-gap: var(--space-small);
&::after {
content: "";
border-bottom: var(--tabstrip-inner-border);
margin-inline: var(--tab-margin-inline-inner);
}
&:not([overflow])::after {
border-color: transparent;
}
@media not -moz-pref("sidebar.visibility", "expand-on-hover") {
/* We need these rules to apply at all times when the sidebar.visibility
pref is not set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has not been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
&:not([expanded])::after {
border-color: transparent;
}
}
.tabbrowser-tab {
flex: none;
padding-inline: 0;
padding-block: var(--tab-padding-block-start) var(--tab-padding-block-end);
/* prevent the shadow of the close button from being cutoff by the toolbar on the first tab */
&:nth-child(1 of :not([hidden], [pinned])) {
padding-block-start: var(--space-xsmall);
}
}
.tab-label-container {
contain: inline-size;
}
.tab-background {
margin-inline: var(--tab-margin-inline-inner);
@media not -moz-pref("browser.nova.enabled") {
/* Needed to flip the direction of the tab-context-line. */
flex-direction: row-reverse;
}
}
&:not([expanded]) {
--tab-close-button-border-color: var(--button-border-color);
--tab-close-button-border-color-hover: var(--button-border-color-hover);
--tab-close-button-border-color-active: var(--button-border-color-active);
.tabbrowser-tab[pinned] {
width: var(--tab-collapsed-width);
}
.tab-background {
width: var(--tab-collapsed-background-width);
}
.tab-label-container {
display: none;
}
.tab-close-button {
opacity: 0;
width: 15px;
height: 15px;
padding: 3.5px;
margin: 0;
/* We want to make this look like the selected tab, but fully opaque. For that,
* we build a stack of `--lwt-accent-color` (guaranteed opaque), then
* `--toolbox-background-color`, then `--tab-background-color-selected`.
*
* We rely on at least one of `--toolbox-background-color` / `--tab-background-color-selected`
* being opaque on the system themes, so even though `--lwt-accent-color` is
* not set there, it ends up working out because we never see it through.
*
* We also apply one extra color on top (--close-button-extra-background)
* for hover / active feedback.
*/
--close-button-extra-background: var(--button-background-color-ghost);
background-color: var(--lwt-accent-color);
background-image: image(var(--close-button-extra-background)), image(var(--tab-background-color-selected)), image(var(--toolbox-background-color));
color-scheme: var(--tab-selected-color-scheme);
color: var(--tab-text-color-selected);
outline-color: var(--tab-close-button-border-color);
box-shadow: var(--tab-box-shadow-selected);
border-radius: var(--border-radius-circle);
display: block;
position: absolute;
inset: auto;
top: -3px;
inset-inline-start: 2px;
/* In forced-colors, --close-button-extra-background will be opaque, and
* foreground needs to match that. Same for the media queries below. */
@media (forced-colors) {
color: var(--button-text-color-ghost);
}
/* Nova: 16px button with a 12px icon box, matching .tab-icon-overlay. */
@media -moz-pref("browser.nova.enabled") {
width: var(--icon-size);
height: var(--icon-size);
padding: 2px;
top: -2px;
box-shadow: var(--box-shadow-level-1);
}
&:-moz-window-inactive {
background-image:
image(var(--close-button-extra-background)), image(var(--tab-background-color-selected)), image(var(--toolbox-background-color-inactive));
}
&:hover {
--close-button-extra-background: var(--button-background-color-ghost-hover);
outline-color: var(--tab-close-button-border-color-hover);
@media (forced-colors) {
color: var(--button-text-color-ghost-hover);
}
}
&:hover:active {
--close-button-extra-background: var(--button-background-color-ghost-active);
outline-color: var(--tab-close-button-border-color-active);
@media (forced-colors) {
color: var(--button-text-color-ghost-active);
}
}
.tabbrowser-tab:hover & {
opacity: 1;
}
&[pinned] {
display: none;
}
@media -moz-pref("sidebar.visibility", "expand-on-hover") {
/* Tab close button when the sidebar is collapsed should
not be shown when expand on hover is enabled because once
you hover over the launcher to use the button, the launcher
starts to expand and the button is no longer shown. Users can
rely on the close button within the tab once expanded.
We need this rule to apply at all times when the sidebar.visibility
pref is set to "expand-on-hover" as opposed to when the "sidebar-expand-on-hover" attribute
has been added to root. There are certain scenarios when that attribute is temporarily
removed from root such as when toggling the sidebar to expand with the toolbar button. */
display: none;
}
}
}
&[expanded] {
--tab-icon-margin-inline-end: 7.5px;
.tabbrowser-tab {
max-width: none;
.tab-content {
/* This 'contain' styling lets us have efficient reflows inside of the
tab, e.g. to hide/show the tab close icon. The drawback of doing
this is that this element won't automagically grow the tab to fit
the height of our contents (the tab label). So, to preserve that
behavior, we use 'contain-intrinsic-block-size' to mock the label's
exact content-size (a single line of text with our hardcoded
tab-label line-height). */
contain: size layout;
line-height: var(--tab-label-line-height);
contain-intrinsic-block-size: 1lh;
}
.tab-close-button {
margin-inline-end: calc(var(--tab-close-button-padding) / -2);
}
&:not(:hover) .tab-close-button:not([selected]) {
visibility: collapse;
}
}
}
}
/* Tab drag and drop */
.tab-drop-indicator {
width: var(--icon-size-xsmall);
margin-inline-start: calc(var(--icon-size-xsmall) * -1);
background: url(chrome://browser/skin/tabbrowser/tab-drag-indicator.svg) no-repeat center;
position: relative;
z-index: 2;
pointer-events: none;
}
.dragfeedback-tab {
appearance: none;
opacity: 0.65;
-moz-window-shadow: none;
}
/* Firefox View button and menu item */
#TabsToolbar #firefox-view-button[open] > .toolbarbutton-icon {
background-color: var(--tab-background-color-selected);
box-shadow: var(--tab-box-shadow-selected);
outline-color: var(--tab-border-color-selected);
color: var(--tab-text-color-selected);
color-scheme: var(--tab-selected-color-scheme);
/* The below lines are required for dark, light, and
system themes to achieve the gradient border appearance */
@media -moz-pref("browser.nova.enabled") and (not ((prefers-contrast) or (-moz-native-theme))) {
:root[theme-in-app] & {
border: 1px solid transparent;
background:
var(--tab-border-color-accent) border-box border-area,
var(--tab-background-color-selected) padding-box;
}
}
}
:root:not([privatebrowsingmode]) :is(toolbarbutton, toolbarpaletteitem),
:root[privatebrowsingmode] :is(toolbarbutton:not(#firefox-view-button), toolbarpaletteitem:not(#wrapper-firefox-view-button)) {
~ #tabbrowser-tabs[orient="horizontal"]::before {
display: flex;
content: "";
border-inline-start: var(--tabstrip-inner-border);
padding-inline-start: 2px;
margin-inline-start: 2px;
}
}
:root[privatebrowsingmode] :is(#firefox-view-button, #menu_openFirefoxView) {
display: none;
}
toolbar:not(#TabsToolbar) #firefox-view-button {
background-position: top 25% right 25%;
/* RTL notification dot */
&:-moz-locale-dir(rtl) {
background-position-x: left 25%;
}
}
:is(#widget-overflow-mainView, #widget-overflow-fixed-list) #firefox-view-button {
background-position: top 25% left 22px;
&:-moz-locale-dir(rtl) {
background-position-x: right 22px;
}
}
/* New tab button */
#tabs-newtab-button,
#vertical-tabs-newtab-button,
#TabsToolbar #new-tab-button {
list-style-image: url(chrome://global/skin/icons/plus.svg);
}
#tabbrowser-tabs[hasadjacentnewtabbutton]:not([overflow]) ~ #new-tab-button,
#tabbrowser-tabs[orient="horizontal"] > #vertical-tabs-newtab-button,
#tabbrowser-tabs[orient="vertical"]:not([overflow]) > #vertical-tabs-newtab-button,
#tabbrowser-arrowscrollbox[overflowing] > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button,
#tabbrowser-tabs:not([hasadjacentnewtabbutton])[orient="horizontal"] > #tabbrowser-arrowscrollbox > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button,
#TabsToolbar[customizing] #tabs-newtab-button {
display: none;
}
/* All tabs button and menupopup */
#alltabs-button {
list-style-image: url("chrome://browser/skin/search-tabs.svg");
@media not (-moz-platform: linux) {
#TabsToolbar & {
list-style-image: url("chrome://global/skin/icons/arrow-down.svg");
}
}
#tabbrowser-tabs[hiddensoundplaying] ~ & > .toolbarbutton-badge-stack > .toolbarbutton-badge {
background: transparent url(chrome://browser/skin/tabbrowser/tab-audio-playing-small.svg);
box-shadow: none;
/* Match the color of the button, rather than label default. */
color: inherit;
display: block;
-moz-context-properties: fill, fill-opacity, stroke;
fill: currentColor;
stroke: transparent;
/* "!important" is necessary to override the rule in toolbarbutton.css */
margin: -7px 0 0 !important;
margin-inline-end: -4px !important;
min-width: var(--icon-size-xsmall);
min-height: var(--icon-size-xsmall);
}
}
#allTabsMenu-allTabsView-tabs {
padding-block: 0;
}
#allTabsMenu-dropIndicatorHolder {
display: block;
position: relative;
}
#allTabsMenu-dropIndicator {
background: url(chrome://browser/skin/tabbrowser/tab-drag-indicator.svg) no-repeat center;
display: block;
position: absolute;
transform: rotate(-90deg);
width: var(--icon-size-xsmall);
height: 29px;
inset-inline-start: 8px;
top: 0;
pointer-events: none;
&:-moz-locale-dir(rtl) {
transform: rotate(90deg);
}
}
#allTabsMenu-groupsView {
&:empty,
&:empty + #allTabsMenu-groupsSeparator {
display: none;
}
}
.all-tabs-item {
border-radius: var(--panel-menuitem-border-radius);
margin-inline: var(--panel-menuitem-margin-inline);
&.grouped {
/* Indent further by the size of a favicon and the favicon's padding-inline-start. */
margin-inline-start: calc(var(--panel-menuitem-margin-inline) + var(--icon-size) + var(--panel-menuitem-padding-inline));
}
&[selected] {
font-weight: var(--font-weight-semibold);
}
> toolbarbutton {
margin: 0;
color: var(--button-text-color-ghost);
background-color: var(--button-background-color-ghost);
&:hover {
color: var(--button-text-color-ghost-hover);
background-color: var(--button-background-color-ghost-hover);
}
&:hover:active {
color: var(--button-text-color-ghost-active);
background-color: var(--button-background-color-ghost-active);
}
&.all-tabs-container-indicator {
position: relative;
&::before {
content: "";
position: absolute;
inset: 2px -3px;
background: var(--identity-tab-color);
width: 2px;
}
/* Show the container icon in a round tinted background at the trailing
edge (next to the close button). */
@media -moz-pref("browser.nova.enabled") {
/* Reserve room so the cropped label ends before the indicator. */
padding-inline-end: calc(24px + var(--space-small));
&::before {
inset: 50% var(--space-xsmall) auto auto;
transform: translateY(-50%);
box-sizing: content-box;
width: 16px;
height: 16px;
padding: var(--space-xsmall);
border-radius: var(--border-radius-circle);
background-color: var(--identity-fill-tint);
background-image: var(--identity-icon);
background-origin: content-box;
background-repeat: no-repeat;
background-position: center;
background-size: 16px;
-moz-context-properties: fill;
fill: var(--identity-fill-color);
}
}
}
}
}
.all-tabs-button {
list-style-image: url("chrome://global/skin/icons/defaultFavicon.svg");
}
.all-tabs-secondary-button {
-moz-context-properties: fill;
fill: currentColor;
> label {
display: none !important; /* override panelUI-shared.css */
}
&:hover {
opacity: 1;
}
}
.all-tabs-mute-button[soundplaying] {
list-style-image: url(chrome://global/skin/media/audio.svg);
}
.all-tabs-mute-button[muted] {
list-style-image: url(chrome://global/skin/media/audio-muted.svg);
}
.all-tabs-close-button {
list-style-image: url(chrome://global/skin/icons/close.svg);
@media not -moz-pref("browser.nova.enabled") {
> .toolbarbutton-icon {
margin-inline: 2px !important; /* override panelUI-shared.css */
}
}
}
.tab-throbber-tabslist {
height: 16px;
width: 16px;
&[busy] {
list-style-image: url("chrome://global/skin/icons/loading.svg");
-moz-context-properties: fill;
fill: currentColor;
opacity: 0.7;
}
&[progress] {
color: var(--tab-icon-fill-loading);
opacity: 1;
}
}
/*
* Tab note icon that displays inline on unpinned tabs in the horizontal tab
* strip and the expanded vertical tab strip. Pinned tabs and the collapsed
* vertical tab strip get a separate space-constrained treatment using the
* `.tab-notes-icon-overlay` image.
*/
.tab-note-icon {
display: none;
box-sizing: border-box;
width: calc(var(--icon-size-xsmall) + 8px);
height: calc(var(--icon-size-xsmall) + 8px);
padding: 4px;
margin-inline-end: var(--tab-note-icon-end-margin);
list-style-image: url("chrome://global/skin/icons/tab-notes-12.svg");
-moz-context-properties: fill;
fill: currentColor;
/* Vertical expanded: reserve space so the note icon does not jump when the close shows.*/
#tabbrowser-tabs[orient="vertical"][expanded] & {
.tabbrowser-tab:not(:hover) & {
/* .tab-close-button is --tab-content-button-size wide with border-box sizing */
margin-inline-end: calc(var(--tab-note-icon-end-margin) + var(--tab-content-button-size) - var(--tab-content-button-padding) / 2);
}
.tabbrowser-tab:is([visuallyselected], :hover) & {
margin-inline-end: var(--tab-note-icon-end-margin);
}
}
}
@media -moz-pref("browser.tabs.notes.enabled") and (not -moz-pref("sidebar.visibility", "expand-on-hover")) {
.tabbrowser-tab[tab-note]:not([pinned]) .tab-note-icon {
#tabbrowser-tabs[orient="horizontal"] &,
#tabbrowser-tabs[orient="vertical"][expanded] & {
display: revert;
}
}
}
/* NOTE(emilio): The double class is an specificity hack to win over the
* .subviewbutton-iconic rules */
.tab-group-icon.tab-group-icon {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-group-chicklet.svg");
--menuitem-icon: url("chrome://browser/skin/tabbrowser/tab-group-chicklet.svg");
--menuitem-icon-fill: light-dark(var(--tab-group-color), var(--tab-group-color-invert));
-moz-context-properties: fill, stroke;
stroke: light-dark(var(--tab-group-color), var(--tab-group-color-invert));
@media -moz-pref("browser.nova.enabled") {
--menuitem-icon-fill: var(--tab-group-background-color);
stroke: var(--tab-group-background-color);
}
> .toolbarbutton-icon {
fill: var(--menuitem-icon-fill);
}
&.tab-group-icon-collapsed {
--menuitem-icon-fill: light-dark(var(--tab-group-color-pale), var(--tab-group-color));
stroke: light-dark(var(--tab-group-color), var(--tab-group-color-pale));
@media -moz-pref("browser.nova.enabled") {
--menuitem-icon-fill: var(--tab-group-background-color);
stroke: var(--tab-group-background-color);
}
}
&.tab-group-icon-closed {
--menuitem-icon-fill: transparent;
stroke: light-dark(var(--tab-group-color), var(--tab-group-color-invert));
@media -moz-pref("browser.nova.enabled") {
stroke: var(--tab-group-background-color);
}
}
}
#tab-group-default-actions {
padding-top: var(--space-medium);
}
#tab-group-default-actions,
#tab-group-suggestions-load-actions,
#tab-group-suggestion-button,
#tab-group-suggestions-message-container {
display: none;
}
#tab-group-suggestions-heading,
#tab-group-main,
#tab-group-suggestions-separator,
#tab-group-suggestions-load-actions,
#tab-group-suggestions-loading,
#tab-group-default-actions,
#tab-group-suggestion-button {
display: flex;
}
#tab-group-suggestions-message-container,
#tab-group-suggestions-container {
display: block;
}
#tab-group-suggestions-disclaimer > a {
display: inline;
color: inherit;
}
#tab-group-suggestions-disclaimer {
display: initial;
}
#tab-group-select-checkbox {
margin-top: 0.5em;
}
#tab-group-suggestion-button {
--button-border-color-ghost: var(--border-color-selected);
color: var(--color-accent-primary);
width: auto;
padding: 0;
@media -moz-pref("browser.nova.enabled") {
padding-block-start: var(--space-medium);
}
&:hover {
--button-border-color-ghost-hover: var(--border-color-selected);
}
}
#tab-group-suggestions {
margin-inline-start: var(--space-xlarge);
margin-block-start: var(--space-xlarge);
display: flex;
flex-direction: column;
gap: var(--space-xlarge);
}
#tab-group-suggestions-loading {
gap: 4px;
flex-direction: column;
margin: 0 8px 8px;
}
#tab-group-suggestions-message-container {
--button-opacity-disabled: 1;
color: inherit;
font-size: 0.85em;
margin-bottom: var(--space-medium);
& > p {
margin-top: 0;
padding-inline: 35px var(--space-medium);
}
}
#tab-group-suggestions-container,
#tab-group-suggestions-optin-container {
margin: var(--panel-menuitem-margin);
@media -moz-pref("browser.nova.enabled") {
margin-block-start: var(--space-medium);
}
}
.tab-group-suggestions-loading-header,
#tab-group-suggestions-header {
margin: 8px 0;
}
@keyframes tab-group-loading-block-animation {
0% {
background-position: 200% 0;
}
50% {
background-position: 0 0;
}
100% {
background-position: -200% 0;
}
}
.tab-group-suggestions-loading-block:nth-of-type(2) {
animation-delay: 0.1s;
}
.tab-group-suggestions-loading-block:nth-of-type(3) {
animation-delay: 0.2s;
}
.tab-group-suggestions-loading-block:nth-of-type(4) {
animation-delay: 0.3s;
}
.tab-group-suggestions-loading-block {
animation: tab-group-loading-block-animation 3s infinite;
outline-color: var(--tab-group-suggestions-loading-animation-color-1);
border-color: var(--tab-group-suggestions-loading-animation-color-2);
background: linear-gradient(
100deg,
color-mix(in srgb, var(--tab-group-suggestions-loading-animation-color-2), transparent 60%) 30%,
var(--tab-group-suggestions-loading-animation-color-1) 50%,
color-mix(in srgb, var(--tab-group-suggestions-loading-animation-color-2), transparent 60%) 70%
);
background-size: 200% 100%;
border-radius: var(--border-radius-small);
height: 1.5em;
margin: 0;
margin-bottom: 0.5em;
padding: 0;
white-space: nowrap;
width: 100%;
}