Use :not(menu):not(menuitem):not(popover):not(window) guards on all wildcard selectors so bar typography and background-color rules don't bleed into SNI popup menus and popovers attached via menuAttachToWidget. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
541 lines
15 KiB
CSS
541 lines
15 KiB
CSS
/* Widget/layout styling for taffybar.
|
|
*
|
|
* Colors live in `theme.css` (loaded via `palette.css`).
|
|
* IMPORTANT: use `@import url("...")` — bare `import` is silently ignored
|
|
* by GTK's CSS parser.
|
|
*/
|
|
@import url("theme.css");
|
|
|
|
/* Base typography + foreground color for the bar itself.
|
|
*
|
|
* IMPORTANT: menus/popovers created by SNI items are separate GtkWindows but
|
|
* inherit style context from the "attach widget" chain. If we apply a blanket
|
|
* `color:` rule here, it will bleed into those menus and override the GTK
|
|
* theme, making submenu text unreadable.
|
|
*/
|
|
.taffy-window .taffy-box :not(menu):not(menuitem):not(popover):not(window),
|
|
.taffy-window .taffy-box :not(menu):not(menuitem):not(popover):not(window) * {
|
|
/* Most text should come from Iosevka Aile; icon glyphs (Font Awesome / Nerd
|
|
Font PUA) should come from a Nerd Font family to avoid tiny fallback glyphs. */
|
|
font-family: "Iosevka Aile", "Iosevka Nerd Font", "Iosevka NF", "Noto Sans", sans-serif;
|
|
font-size: 11pt;
|
|
font-weight: 600;
|
|
color: @font-color;
|
|
text-shadow: none;
|
|
}
|
|
|
|
/* Icon-label combined widgets (PulseAudio, NetworkManager): the `.icon` label
|
|
uses a nerd font character, so force the nerd font family on it. */
|
|
.icon-label > .icon {
|
|
font-family: "Iosevka Nerd Font";
|
|
padding-right: 11px;
|
|
}
|
|
|
|
/* The main bar container. border-radius matches the widget squircles (6px)
|
|
so the bar itself has softly rounded corners. */
|
|
.taffy-box {
|
|
border-width: 0px;
|
|
padding: 0px;
|
|
margin: 0px;
|
|
border-radius: 6px;
|
|
box-shadow: none;
|
|
background-color: @bar-background;
|
|
background-image: none;
|
|
}
|
|
|
|
/* Each widget is wrapped in outer-pad > inner-pad > contents by
|
|
buildContentsBox (Haskell). The outer-pad draws the squircle
|
|
background pill. border-radius kept low (6px) for a more squared
|
|
"squircle" shape rather than a fully rounded pill. */
|
|
.outer-pad {
|
|
background-color: @pill-background;
|
|
border: 0px;
|
|
border-radius: 6px;
|
|
margin: 4px 6px;
|
|
/* No white outline; define shape with subtle inner highlight + dark stroke. */
|
|
box-shadow:
|
|
inset 0 1px 0 @pill-highlight,
|
|
inset 0 0 0 1px @pill-border,
|
|
0 10px 24px @pill-shadow;
|
|
}
|
|
|
|
.inner-pad {
|
|
padding: 2px 10px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.contents {
|
|
padding: 0px;
|
|
transition: background-color .2s;
|
|
opacity: 1;
|
|
}
|
|
|
|
/* Make each widget's squircle background feel "solid": avoid GTK nodes and
|
|
labels painting their own backgrounds on top of `.outer-pad`.
|
|
Exclude menu/menuitem/popover so popup menus attached via menuAttachToWidget
|
|
aren't forced transparent. */
|
|
.outer-pad :not(menu):not(menuitem):not(popover):not(window),
|
|
.inner-pad,
|
|
.inner-pad :not(menu):not(menuitem):not(popover):not(window),
|
|
.inner-pad :not(menu):not(menuitem):not(popover):not(window) *,
|
|
.contents,
|
|
.contents :not(menu):not(menuitem):not(popover):not(window),
|
|
.contents :not(menu):not(menuitem):not(popover):not(window) * {
|
|
background-color: transparent;
|
|
}
|
|
|
|
/* Per-widget colored squircle overrides.
|
|
decorateWithClassAndBox "name" (in taffybar.hs) adds the widget class to
|
|
the same element that has .outer-pad, so `.outer-pad.audio` etc. target
|
|
each widget's pill. Colors come from @widget-*-bg/fg/border in theme.css. */
|
|
.outer-pad.audio {
|
|
background-color: @widget-audio-bg;
|
|
border-color: @widget-audio-border;
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
|
|
}
|
|
.outer-pad.audio :not(menu):not(menuitem):not(popover):not(window),
|
|
.outer-pad.audio :not(menu):not(menuitem):not(popover):not(window) * {
|
|
color: @widget-audio-fg;
|
|
}
|
|
|
|
.outer-pad.network {
|
|
background-color: @widget-network-bg;
|
|
border-color: @widget-network-border;
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
|
|
}
|
|
.outer-pad.network :not(menu):not(menuitem):not(popover):not(window),
|
|
.outer-pad.network :not(menu):not(menuitem):not(popover):not(window) * {
|
|
color: @widget-network-fg;
|
|
}
|
|
|
|
.outer-pad.mpris {
|
|
background-color: @widget-mpris-bg;
|
|
border-color: @widget-mpris-border;
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
|
|
}
|
|
.outer-pad.mpris :not(menu):not(menuitem):not(popover):not(window),
|
|
.outer-pad.mpris :not(menu):not(menuitem):not(popover):not(window) * {
|
|
color: @widget-mpris-fg;
|
|
}
|
|
.outer-pad.mpris .icon {
|
|
font-family: "Iosevka Nerd Font";
|
|
}
|
|
|
|
.outer-pad.clock {
|
|
background-color: @widget-clock-bg;
|
|
border-color: @widget-clock-border;
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
|
|
}
|
|
.outer-pad.clock :not(menu):not(menuitem):not(popover):not(window),
|
|
.outer-pad.clock :not(menu):not(menuitem):not(popover):not(window) * {
|
|
color: @widget-clock-fg;
|
|
}
|
|
|
|
.outer-pad.disk-usage {
|
|
background-color: @widget-disk-bg;
|
|
border-color: @widget-disk-border;
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
|
|
}
|
|
.outer-pad.disk-usage :not(menu):not(menuitem):not(popover):not(window),
|
|
.outer-pad.disk-usage :not(menu):not(menuitem):not(popover):not(window) * {
|
|
color: @widget-disk-fg;
|
|
}
|
|
|
|
.outer-pad.sni-tray {
|
|
background-color: @widget-tray-bg;
|
|
border-color: @widget-tray-border;
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
|
|
}
|
|
.outer-pad.sni-tray :not(menu):not(menuitem):not(popover):not(window),
|
|
.outer-pad.sni-tray :not(menu):not(menuitem):not(popover):not(window) * {
|
|
color: @widget-tray-fg;
|
|
}
|
|
|
|
.outer-pad.battery {
|
|
background-color: @widget-battery-bg;
|
|
border-color: @widget-battery-border;
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
|
|
}
|
|
.outer-pad.battery :not(menu):not(menuitem):not(popover):not(window),
|
|
.outer-pad.battery :not(menu):not(menuitem):not(popover):not(window) * {
|
|
color: @widget-battery-fg;
|
|
}
|
|
|
|
.outer-pad.backlight {
|
|
background-color: @widget-backlight-bg;
|
|
border-color: @widget-backlight-border;
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
|
|
}
|
|
.outer-pad.backlight :not(menu):not(menuitem):not(popover):not(window),
|
|
.outer-pad.backlight :not(menu):not(menuitem):not(popover):not(window) * {
|
|
color: @widget-backlight-fg;
|
|
}
|
|
|
|
/* Workspaces styling */
|
|
|
|
/* Asymmetric padding: 10px left leaves room for the overlaid workspace number
|
|
label; 3px right keeps the pill tight against the trailing icon edge. */
|
|
.workspaces .inner-pad {
|
|
box-shadow: none;
|
|
border-width: 0;
|
|
padding: 2px 3px 2px 10px;
|
|
}
|
|
|
|
.workspaces .contents {
|
|
box-shadow: none;
|
|
border-radius: 5px;
|
|
border-width: 0px;
|
|
border-style: solid;
|
|
border-color: @transparent;
|
|
padding: 0px 4px;
|
|
}
|
|
|
|
.workspace-label {
|
|
/* Overlay label (workspace number) that sits inside the icon "squircle". */
|
|
padding: 1px 3px;
|
|
margin: 0px;
|
|
font-size: 10pt;
|
|
opacity: 0.92;
|
|
font-weight: 700;
|
|
transition: color .2s;
|
|
background-color: @transparent;
|
|
}
|
|
|
|
/* The workspace label is overlaid bottom-left over the workspace icon strip.
|
|
Positioning: halign=start (left), valign=end (bottom) set in Haskell code.
|
|
Margins offset from that anchor point. */
|
|
.workspaces .overlay-box {
|
|
transition: background-color .2s, border-color .2s;
|
|
|
|
background-color: transparent;
|
|
border: none;
|
|
margin: 0px;
|
|
padding: 0px;
|
|
}
|
|
|
|
/* Position the workspace number inside the squircle pill. GTK overlays ignore
|
|
CSS margin for child positioning, so we use padding on the label itself:
|
|
padding-bottom pushes the text up from the bottom edge, padding-left pushes
|
|
it inward from the left corner to clear the border-radius. */
|
|
.workspaces .overlay-box .workspace-label {
|
|
background-color: transparent;
|
|
border: none;
|
|
padding: 2px 5px 5px 12px;
|
|
color: rgba(255, 255, 255, 0.92);
|
|
}
|
|
|
|
/* Accent-tinted background on the active workspace's squircle pill.
|
|
.active is set on the GtkOverlay (by setWorkspaceWidgetStatusClass in
|
|
Haskell), and .outer-pad is a child of that overlay, so
|
|
`.workspaces .active .outer-pad` correctly targets the pill. */
|
|
.workspaces .active .outer-pad {
|
|
background-color: rgba(241, 178, 178, 0.25);
|
|
box-shadow:
|
|
inset 0 0 0 1px rgba(241, 178, 178, 0.5),
|
|
inset 0 1px 0 @pill-highlight,
|
|
0 10px 24px @pill-shadow;
|
|
}
|
|
|
|
.workspaces .active .overlay-box {
|
|
background-color: transparent;
|
|
border-color: transparent;
|
|
}
|
|
|
|
.contents .window-icon {
|
|
border-width: 3px;
|
|
}
|
|
|
|
.active .contents .window-icon {
|
|
opacity: 1;
|
|
}
|
|
|
|
.active .contents {
|
|
background-color: rgba(255, 255, 255, 0.10);
|
|
opacity: 1;
|
|
}
|
|
|
|
/* (Handled above for workspaces.) */
|
|
|
|
.visible .contents {
|
|
background-color: rgba(255, 255, 255, 0.06);
|
|
}
|
|
|
|
.workspaces .window-icon-container {
|
|
/* Don't give each window icon its own background/border; the workspace
|
|
squircle is the background. */
|
|
background-color: transparent;
|
|
border: 0px;
|
|
box-shadow: none;
|
|
padding: 0px 2px;
|
|
}
|
|
|
|
.workspaces .window-icon-container.active {
|
|
background-color: rgba(255, 255, 255, 0.10);
|
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
border-radius: 4px;
|
|
padding: 2px 4px;
|
|
}
|
|
|
|
.workspaces .active .contents,
|
|
.workspaces .visible .contents {
|
|
background-color: transparent;
|
|
}
|
|
|
|
.workspaces .window-icon {
|
|
border-width: 0px;
|
|
}
|
|
|
|
.window-icon-container {
|
|
transition: opacity .2s, box-shadow .2s;
|
|
opacity: 1;
|
|
border-radius: 5px;
|
|
transition: background-color .2s;
|
|
background-color: rgba(255, 255, 255, 0.04);
|
|
padding: 1px 4px;
|
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
}
|
|
|
|
/* This gives space for the box-shadow (they look like underlines) that follow.
|
|
This will actually affect all widgets, (not just the workspace icons), but
|
|
that is what we want since we want the icons to look the same. */
|
|
.auto-size-image, .sni-tray {
|
|
padding: 1px 4px;
|
|
}
|
|
|
|
/* If the SNI tray is wrapped in our standard widget box, avoid double-padding. */
|
|
.sni-tray .sni-tray {
|
|
padding: 0px;
|
|
}
|
|
|
|
.window-icon-container.active {
|
|
background-color: rgba(255, 255, 255, 0.13);
|
|
border-color: rgba(255, 255, 255, 0.16);
|
|
}
|
|
|
|
.window-icon-container.urgent {
|
|
}
|
|
|
|
.window-icon-container.minimized .window-icon {
|
|
opacity: .3;
|
|
}
|
|
|
|
.window-icon {
|
|
opacity: 1;
|
|
transition: opacity .5s;
|
|
}
|
|
|
|
/* Button styling */
|
|
|
|
.taffy-window button {
|
|
all: initial;
|
|
background-color: @transparent;
|
|
border-width: 0px;
|
|
border-radius: 0px;
|
|
}
|
|
|
|
|
|
.taffy-window button:checked, .taffy-window button:hover .Contents:hover {
|
|
box-shadow: inset 0 -2px @accent;
|
|
background-color: rgba(255, 255, 255, 0.06);
|
|
}
|
|
|
|
/* ── Menu styling ───────────────────────────────────────────────────────
|
|
Force a clean white-background / black-text look on all popup menus
|
|
(GtkMenu, DBusMenu, popovers) regardless of the active GTK theme.
|
|
The CSS provider runs at priority 900 (above USER = 800).
|
|
The .outer-pad background rule uses :not(menu):not(menuitem) to avoid
|
|
forcing transparency on popup menu containers. For color, we need
|
|
high-specificity overrides since labels inside menus still match :not(menu). */
|
|
|
|
/* --- Popup menu containers ---
|
|
.taffy-window menu (0,1,1) beats .taffy-window * (0,1,0) for background.
|
|
.outer-pad.sni-tray menu (0,2,1) beats .outer-pad.sni-tray * (0,2,0). */
|
|
menu,
|
|
.taffy-window menu,
|
|
.outer-pad menu {
|
|
background-color: #ffffff;
|
|
background-image: none;
|
|
color: #000000;
|
|
font-family: "Noto Sans", sans-serif;
|
|
font-size: 10pt;
|
|
font-weight: 400;
|
|
text-shadow: none;
|
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
border-radius: 6px;
|
|
padding: 4px 0;
|
|
}
|
|
|
|
/* --- Menu items ---
|
|
High specificity to beat .outer-pad.sni-tray * color bleed (0,2,0). */
|
|
.outer-pad.sni-tray menu menuitem,
|
|
.outer-pad menu menuitem,
|
|
.taffy-window menu menuitem,
|
|
menu menuitem {
|
|
background-color: #ffffff;
|
|
background-image: none;
|
|
color: #000000;
|
|
font-family: "Noto Sans", sans-serif;
|
|
font-size: 10pt;
|
|
font-weight: 400;
|
|
text-shadow: none;
|
|
padding: 4px 12px;
|
|
min-height: 20px;
|
|
}
|
|
|
|
/* Children: transparent bg so hover shows through; override color bleed.
|
|
Use :not(menu) to avoid forcing transparency on nested submenu containers. */
|
|
.outer-pad.sni-tray menu menuitem :not(menu),
|
|
.outer-pad menu menuitem :not(menu),
|
|
.taffy-window menu menuitem :not(menu),
|
|
menu menuitem :not(menu) {
|
|
background-color: transparent;
|
|
background-image: none;
|
|
color: #000000;
|
|
font-family: "Noto Sans", sans-serif;
|
|
font-size: 10pt;
|
|
font-weight: 400;
|
|
text-shadow: none;
|
|
}
|
|
|
|
/* --- Hover --- */
|
|
.outer-pad.sni-tray menu menuitem:hover,
|
|
.outer-pad menu menuitem:hover,
|
|
menu menuitem:hover {
|
|
background-color: #4a90d9;
|
|
}
|
|
|
|
.outer-pad.sni-tray menu menuitem:hover :not(menu),
|
|
.outer-pad menu menuitem:hover :not(menu),
|
|
menu menuitem:hover :not(menu),
|
|
menu menuitem:hover {
|
|
color: #ffffff;
|
|
}
|
|
|
|
/* --- Separators --- */
|
|
menuitem separator {
|
|
background-color: transparent;
|
|
min-height: 1px;
|
|
margin: 4px 8px;
|
|
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
|
}
|
|
|
|
/* --- Arrows & toggle indicators --- */
|
|
menuitem arrow {
|
|
background-color: transparent;
|
|
color: rgba(0, 0, 0, 0.4);
|
|
}
|
|
|
|
menuitem check, menuitem radio {
|
|
background-color: transparent;
|
|
color: #000000;
|
|
}
|
|
|
|
/* --- Background/decoration nodes in popup windows ---
|
|
Submenus are separate popup windows that may NOT be CSS descendants of
|
|
.taffy-window or .outer-pad. Cover every popup window layer. */
|
|
window.popup, window.popup.background,
|
|
window.menu, window.menu.background {
|
|
background-color: #ffffff;
|
|
background-image: none;
|
|
}
|
|
|
|
window.popup decoration, window.menu decoration {
|
|
background-color: #ffffff;
|
|
background-image: none;
|
|
}
|
|
|
|
/* Catch submenus that aren't CSS descendants of .taffy-window/.outer-pad.
|
|
Use .dbusmenu-submenu class (added by DBusMenu.hs) plus type selectors. */
|
|
/* Submenu rules need specificity > 0,2,0 to beat .outer-pad.sni-tray *
|
|
which bleeds tray colors into submenus via the CSS parent chain. */
|
|
.outer-pad .dbusmenu-submenu,
|
|
.dbusmenu-submenu {
|
|
background-color: #ffffff;
|
|
background-image: none;
|
|
color: #000000;
|
|
font-family: "Noto Sans", sans-serif;
|
|
font-size: 10pt;
|
|
font-weight: 400;
|
|
text-shadow: none;
|
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
border-radius: 6px;
|
|
padding: 4px 0;
|
|
}
|
|
|
|
.outer-pad.sni-tray .dbusmenu-submenu menuitem,
|
|
.outer-pad .dbusmenu-submenu menuitem,
|
|
.dbusmenu-submenu menuitem {
|
|
background-color: #ffffff;
|
|
background-image: none;
|
|
color: #000000;
|
|
font-family: "Noto Sans", sans-serif;
|
|
font-size: 10pt;
|
|
font-weight: 400;
|
|
text-shadow: none;
|
|
padding: 4px 12px;
|
|
min-height: 20px;
|
|
}
|
|
|
|
.outer-pad.sni-tray .dbusmenu-submenu menuitem *,
|
|
.outer-pad .dbusmenu-submenu menuitem *,
|
|
.dbusmenu-submenu menuitem * {
|
|
background-color: transparent;
|
|
background-image: none;
|
|
color: #000000;
|
|
font-family: "Noto Sans", sans-serif;
|
|
font-size: 10pt;
|
|
font-weight: 400;
|
|
text-shadow: none;
|
|
}
|
|
|
|
.outer-pad.sni-tray .dbusmenu-submenu menuitem:hover,
|
|
.outer-pad .dbusmenu-submenu menuitem:hover,
|
|
.dbusmenu-submenu menuitem:hover {
|
|
background-color: #4a90d9;
|
|
}
|
|
|
|
.outer-pad.sni-tray .dbusmenu-submenu menuitem:hover *,
|
|
.outer-pad .dbusmenu-submenu menuitem:hover *,
|
|
.dbusmenu-submenu menuitem:hover *,
|
|
.outer-pad.sni-tray .dbusmenu-submenu menuitem:hover,
|
|
.dbusmenu-submenu menuitem:hover {
|
|
color: #ffffff;
|
|
}
|
|
|
|
/* --- Popovers (some SNI apps use these instead of GtkMenu) --- */
|
|
popover, popover.background, popover > contents {
|
|
background-color: #ffffff;
|
|
background-image: none;
|
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
border-radius: 6px;
|
|
}
|
|
|
|
popover *, popover modelbutton, popover modelbutton * {
|
|
background-color: transparent;
|
|
color: #000000;
|
|
font-family: "Noto Sans", sans-serif;
|
|
font-size: 10pt;
|
|
font-weight: 400;
|
|
text-shadow: none;
|
|
}
|
|
|
|
popover modelbutton {
|
|
background-color: #ffffff;
|
|
padding: 4px 12px;
|
|
}
|
|
|
|
popover modelbutton:hover {
|
|
background-color: #4a90d9;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.clock label,
|
|
.mpris label,
|
|
.battery label {
|
|
letter-spacing: 0.2px;
|
|
}
|
|
|
|
.mpris label {
|
|
color: @font-muted;
|
|
}
|