Files
redmine-theme-tonalmine/tonalmine/stylesheets/components.css
T
Andreas Reinhold / reiniandClaude Opus 5.5 906153014b fix: structure calendar/Gantt hover cards into title and field grid
- Regroup Redmine's "<strong>Label</strong>: value<br>" tooltip lines on
  first hover into a title block and a label/value grid (theme.js).
- Style the issue link as a kicker, the subject as title-small, and the
  labels as a muted column next to aligned values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 12:44:19 +02:00

619 lines
29 KiB
CSS

/*
* Components: buttons, text fields, cards/boxes, banners, tabs, badges,
* pagination, progress, tooltips, dialogs, date picker, autocomplete.
* Uses --nm-state-* from layout.css.
*/
/***** Buttons *****/
input[type="submit"], input[type="button"], input[type="reset"], button[type="submit"] {
block-size: 40px;
padding-block: 0;
padding-inline: 24px;
margin-block: 4px;
border: 1px solid var(--md-sys-color-outline);
border-radius: var(--md-sys-shape-corner-full);
background-color: transparent;
color: var(--md-sys-color-primary);
font: var(--md-sys-typescale-label-large);
letter-spacing: var(--md-sys-typescale-label-large-tracking);
cursor: pointer;
transition: var(--nm-transition), box-shadow var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
/* Filled: the main action of a form */
input[type="submit"], button[type="submit"] {
border-color: transparent;
background-color: var(--md-sys-color-primary);
color: var(--md-sys-color-on-primary);
}
/* Tonal: "Create and continue" and similar secondary submits */
input[type="submit"][name="continue"], input[type="submit"][name="follow"] {
background-color: var(--md-sys-color-secondary-container);
color: var(--md-sys-color-on-secondary-container);
}
input[type="submit"]:hover, input[type="button"]:hover, input[type="reset"]:hover, button[type="submit"]:hover {
background-image: var(--nm-state-hover);
}
input[type="submit"]:hover, button[type="submit"]:hover { background-color: var(--md-sys-color-primary); box-shadow: var(--md-sys-elevation-level1); }
input[type="submit"][name="continue"]:hover, input[type="submit"][name="follow"]:hover { background-color: var(--md-sys-color-secondary-container); }
input[type="submit"]:active, input[type="button"]:active, button[type="submit"]:active { background-image: var(--nm-state-pressed); box-shadow: none; }
input[type="submit"]:disabled, input[type="button"]:disabled, button:disabled {
background-color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-container-opacity), transparent);
border-color: transparent;
color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-content-opacity), transparent);
box-shadow: none;
cursor: default;
}
/***** Text fields (outlined) *****/
input[type="text"], input[type="password"], input[type="email"], input[type="url"], input[type="number"],
input[type="date"], input[type="search"], input[type="tel"], input:not([type]), select, textarea {
min-block-size: 40px;
padding-block: 8px;
padding-inline: 12px;
border: 1px solid var(--md-sys-color-outline);
border-radius: var(--md-sys-shape-corner-extra-small);
background-color: transparent;
color: var(--md-sys-color-on-surface);
font: var(--md-sys-typescale-body-medium);
letter-spacing: var(--md-sys-typescale-body-medium-tracking);
transition: border-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
input[type="text"]:hover, input[type="password"]:hover, input[type="email"]:hover, input[type="url"]:hover,
input[type="number"]:hover, input[type="date"]:hover, input[type="search"]:hover, select:hover, textarea:hover {
border-color: var(--md-sys-color-on-surface);
}
input[type="text"]:focus, input[type="text"]:active,
input[type="password"]:focus, input[type="password"]:active,
input[type="email"]:focus, input[type="url"]:focus, input[type="search"]:focus,
input[type="date"]:focus, input[type="date"]:active,
input[type="number"]:focus, input[type="number"]:active,
select:focus, select:active,
textarea:focus, textarea:active {
border-color: var(--md-sys-color-primary);
outline: 1px solid var(--md-sys-color-primary); /* 1px border + 1px outline = M3's 2px focused outline without layout shift */
outline-offset: -2px;
}
select {
background-color: transparent;
background-image: url(../images/arrow-drop-down.svg);
background-position: calc(100% - 6px) 50%;
background-size: 24px;
padding-inline-end: 32px;
}
[dir="rtl"] select { background-position: 6px 50%; }
/* The chevron is an image, so it cannot use color roles: one file per mode.
:where() keeps the swap at select's specificity so select[multiple] below still drops it */
:where(:root[data-mode="dark"]) select { background-image: url(../images/arrow-drop-down-dark.svg); }
@media (prefers-color-scheme: dark) { :where(:root:not([data-mode="light"])) select { background-image: url(../images/arrow-drop-down-dark.svg); } }
/* Autocomplete fields (parent task, watchers): M3 leading search icon, same per-mode files */
input.autocomplete {
background: transparent url(../images/search.svg) no-repeat 12px 50% / 20px;
padding-inline-start: 40px !important; /* core sets 20px with !important */
}
[dir="rtl"] input.autocomplete { background-position: calc(100% - 12px) 50%; }
/* :where() keeps the mode swap at the base rule's specificity, so core's own cases still win:
the jump box search (own icon, no background) and the ajax-loading spinner */
:where(:root[data-mode="dark"]) input.autocomplete { background-image: url(../images/search-dark.svg); }
@media (prefers-color-scheme: dark) { :where(:root:not([data-mode="light"])) input.autocomplete { background-image: url(../images/search-dark.svg); } }
select[multiple] { background-image: none; padding-inline-end: 12px; }
input::placeholder, textarea::placeholder { color: var(--md-sys-color-on-surface-variant); opacity: 1; }
input[type="checkbox"], input[type="radio"] { accent-color: var(--md-sys-color-primary); }
input[type="file"] { color: var(--md-sys-color-on-surface-variant); }
input[type="file"]::file-selector-button {
block-size: 40px;
margin-inline-end: 12px;
padding-inline: 24px;
border: 0;
border-radius: var(--md-sys-shape-corner-full);
background-color: var(--md-sys-color-secondary-container);
color: var(--md-sys-color-on-secondary-container);
font: var(--md-sys-typescale-label-large);
cursor: pointer;
}
input:disabled, select:disabled, textarea:disabled {
border-color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-container-opacity), transparent);
color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-content-opacity), transparent);
}
/***** Cards: .box, tabular forms, fieldsets *****/
.box {
padding: 16px;
margin-block-end: 16px;
background-color: var(--md-sys-color-surface-container-low);
color: var(--md-sys-color-on-surface);
border: 0;
border-radius: var(--md-sys-shape-corner-medium);
line-height: 1.5;
}
/* M3 has no legend notched into a border. A fieldset on its own is a filled card with the
legend as headline inside. A fieldset inside a card or form, and a collapsible one, is a
section: a full-width divider with the legend as subheader below it (M3 divider guidance). */
fieldset {
padding: 16px;
margin-block-end: 16px;
border: 0;
border-radius: var(--md-sys-shape-corner-medium);
background-color: var(--md-sys-color-surface-container-low);
}
:is(.box, fieldset) fieldset, fieldset.collapsible:not(.box) {
padding: 8px 0 0;
margin-block: 8px;
border: 0;
border-block-start: 1px solid var(--md-sys-color-outline-variant);
border-radius: 0;
background-color: transparent;
}
/* A section that opens its card needs no divider: the card edge already separates it */
:is(.box, fieldset) > fieldset:first-child { margin-block-start: 0; padding-block-start: 0; border-block-start: 0; }
/* Floated, the legend leaves the border and flows as the first line of the fieldset */
fieldset > legend {
float: inline-start;
inline-size: 100%;
padding: 0 0 8px;
color: var(--md-sys-color-on-surface-variant);
font: var(--md-sys-typescale-title-small);
letter-spacing: var(--md-sys-typescale-title-small-tracking);
}
fieldset > legend ~ * { clear: inline-start; }
fieldset.collapsed > legend { padding-block-end: 0; }
/* The chevron stays with a label that wraps */
fieldset.collapsible > legend { display: flex; align-items: center; gap: 4px; }
.tabular label { color: var(--md-sys-color-on-surface-variant); font-weight: 500; }
.tabular p { padding-block: 4px; }
/* Center the 24px label line on the 40px fields next to it */
.tabular label:not(.floating):not(.block):not(.inline):not(.no-css) { padding-block-start: 8px; }
/* Checkboxes and radios placed directly in a row align with that label line too */
/* Checkboxes and radios next to such a label align with its text line */
.tabular p:has(> label:not(.floating):not(.block):not(.inline):not(.no-css)) > input:is([type="checkbox"], [type="radio"]) { margin-block: 13px 0; }
/* Rows without a field at the label's height start at the top: checkbox lists (watchers)
and the issue description, whose editor stays hidden until "Edit" is clicked */
.tabular p:is(:has(label.floating), :has(> #issue_description_and_toolbar[style*="none"])) > label:not(.floating):not(.block):not(.inline):not(.no-css) { padding-block-start: 0; }
hr { background: var(--md-sys-color-outline-variant); }
blockquote { border-inline-start: 4px solid var(--md-sys-color-outline-variant); color: var(--md-sys-color-on-surface-variant); }
/* Core gives wide form fields 90%, 95% or 99% and caps .tabular fields at 95%. They all
run to the content edge, so the right edges in a form line up */
.tabular :is(input, select) { max-inline-size: 100%; }
#user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select { inline-size: 100%; }
.tabular textarea, textarea.wiki-edit, textarea.text_cf, input.string_cf, input.link_cf,
textarea#custom_field_possible_values, textarea#custom_field_default_value,
input#issue_subject, input#document_title, input#content_comments, input#time_entry_comments,
.tabular .jstTabs, .tabular .wiki-preview, .jstBlock .jstTabs, .jstBlock .wiki-preview { inline-size: 100%; box-sizing: border-box; }
/* An invalid field keeps the error colour while focused */
.tabular label.error + :is(input, select, textarea):focus {
border-color: var(--md-sys-color-error);
outline-color: var(--md-sys-color-error);
}
/* Rows without a field start at the top, like a row with only links (two-factor auth) */
.tabular p:not(:has(input:not([type=hidden]), select, textarea)) > label:not(.floating):not(.block):not(.inline):not(.no-css) { padding-block-start: 0; }
/* Cancel next to a submit button */
input[type="submit"] + a { margin-inline-start: 8px; }
/* Checkbox lists in forms (custom field values, notified projects) */
.check_box_group {
padding-block: 4px;
padding-inline: 8px;
border-color: var(--md-sys-color-outline);
border-radius: var(--md-sys-shape-corner-extra-small);
background-color: transparent;
}
/***** Banners: flash messages, errors, warnings, empty states *****/
#errorExplanation, div.flash, .nodata, .warning, .conflict {
border: 0;
border-radius: var(--md-sys-shape-corner-medium);
padding-block: 14px;
padding-inline: 48px 16px;
font: var(--md-sys-typescale-body-large);
letter-spacing: var(--md-sys-typescale-body-large-tracking);
}
div.flash svg.icon-svg, #errorExplanation svg.icon-svg, .conflict svg.icon-svg { margin-inline: -32px 8px; }
div.flash.error, #errorExplanation {
background-color: var(--md-sys-color-error-container);
color: var(--md-sys-color-on-error-container);
}
div.flash.notice {
background-color: var(--md-sys-color-success-container);
color: var(--md-sys-color-on-success-container);
}
div.flash.warning, .conflict {
background-color: var(--md-sys-color-warning-container);
color: var(--md-sys-color-on-warning-container);
}
.nodata, .warning {
padding-inline: 16px;
background-color: var(--md-sys-color-surface-container);
color: var(--md-sys-color-on-surface-variant);
}
div.flash.error svg.icon-svg, #errorExplanation svg.icon-svg,
div.flash.notice svg.icon-svg, div.flash.warning svg.icon-svg, .conflict svg.icon-svg { stroke: currentColor; }
/***** Secondary tabs (settings, history, admin) *****/
#content .tabs { block-size: 48px; margin-block-end: 16px; }
#content .tabs ul { padding-inline-start: 0; border-block-end: 1px solid var(--md-sys-color-outline-variant); }
#content .tabs ul li { margin-inline-end: 0; margin-block-end: 0; }
#content .tabs ul li a, #content .tabs ul li a:hover {
position: relative;
padding-block: 14px;
padding-inline: 16px;
border: 0;
border-radius: 0;
background-color: transparent;
box-shadow: none;
color: var(--md-sys-color-on-surface-variant);
font: var(--md-sys-typescale-title-small);
letter-spacing: var(--md-sys-typescale-title-small-tracking);
}
#content .tabs ul li a:hover { background-image: var(--nm-state-hover); color: var(--md-sys-color-on-surface); }
#content .tabs ul li a.selected, #content .tabs ul li a.selected:hover {
background-color: transparent;
border: 0;
box-shadow: inset 0 -2px 0 var(--md-sys-color-primary);
color: var(--md-sys-color-on-surface);
}
/* Scroll arrows for tabs that overflow: standard icon buttons at the end of the tab row */
#content .tabs div.tabs-buttons {
display: flex;
align-items: center;
justify-content: end;
gap: 4px;
inline-size: auto;
block-size: 48px;
padding-inline-start: 8px;
box-sizing: border-box;
background: var(--md-sys-color-surface);
border-block-end: 1px solid var(--md-sys-color-outline-variant);
}
#content .tabs button.tab-left, #content .tabs button.tab-right,
#main-menu button.tab-left, #main-menu button.tab-right {
position: static;
display: inline-flex;
align-items: center;
justify-content: center;
inline-size: 40px;
block-size: 40px;
padding: 0;
border: 0;
border-radius: var(--md-sys-shape-corner-full);
background-color: transparent;
color: var(--md-sys-color-on-surface-variant);
}
:is(#content .tabs, #main-menu) button:is(.tab-left, .tab-right) svg.icon-svg { stroke: currentColor; }
:is(#content .tabs, #main-menu) button:is(.tab-left, .tab-right):hover { background-image: var(--nm-state-hover); }
:is(#content .tabs, #main-menu) button:is(.tab-left, .tab-right).disabled {
background: transparent;
color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-content-opacity), transparent);
}
/***** Badges *****/
.badge {
inset-block-end: 2px;
padding-block: 2px;
padding-inline: 6px;
border-radius: var(--md-sys-shape-corner-small);
font: var(--md-sys-typescale-label-small);
letter-spacing: var(--md-sys-typescale-label-small-tracking);
}
.badge-private { background: var(--md-sys-color-error); border-color: var(--md-sys-color-error); color: var(--md-sys-color-on-error); }
.badge-count, .badge-issues-count {
border-radius: var(--md-sys-shape-corner-full);
background: var(--md-sys-color-secondary-container);
color: var(--md-sys-color-on-secondary-container);
}
.badge-status-open { border-color: var(--md-sys-color-primary); color: var(--md-sys-color-primary); }
.badge-status-closed { border-color: var(--md-sys-color-success); color: var(--md-sys-color-success); }
.badge-status-locked { border-color: var(--md-sys-color-outline); color: var(--md-sys-color-on-surface-variant); }
/***** Pagination *****/
span.pagination { margin-inline-start: 0; color: var(--md-sys-color-on-surface-variant); }
.pagination ul.pages { margin-inline: 0 8px; }
.pagination ul.pages li,
.pagination ul.pages li:first-child,
.pagination ul.pages li:last-child {
margin-inline-end: 4px;
border: 0;
border-radius: var(--md-sys-shape-corner-full);
line-height: 40px;
min-inline-size: 40px;
}
.pagination ul.pages li a, .pagination ul.pages li span {
display: block;
padding-block: 0;
padding-inline: 12px;
border-radius: var(--md-sys-shape-corner-full);
color: var(--md-sys-color-on-surface-variant);
}
.pagination ul.pages li.page:hover { background-color: transparent; background-image: var(--nm-state-hover); }
.pagination ul.pages li.page a:hover { color: var(--md-sys-color-on-surface); text-decoration: none; }
.pagination ul.pages li.current {
background-color: var(--md-sys-color-secondary-container);
color: var(--md-sys-color-on-secondary-container);
font-weight: 500;
}
.pagination ul.pages li.current span { color: inherit; }
/***** Linear progress *****/
table.progress { border-radius: var(--md-sys-shape-corner-full); overflow: hidden; }
table.progress td { block-size: 4px; padding: 0; }
.version-overview table.progress td { block-size: 8px; }
table.progress td.closed { background: var(--md-sys-color-primary); }
table.progress td.done { background: color-mix(in srgb, var(--md-sys-color-primary) 55%, var(--md-sys-color-secondary-container)); }
table.progress td.todo { background: var(--md-sys-color-secondary-container); }
/***** Tooltips (plain) *****/
/* jQuery UI also adds .ui-widget.ui-widget-content, which would win over a bare .ui-tooltip. */
.ui-tooltip.ui-widget.ui-widget-content {
background: var(--md-sys-color-inverse-surface);
color: var(--md-sys-color-inverse-on-surface);
border: 0;
border-radius: var(--md-sys-shape-corner-extra-small);
box-shadow: none;
font: var(--md-sys-typescale-body-small);
letter-spacing: var(--md-sys-typescale-body-small-tracking);
padding-block: 4px;
padding-inline: 8px;
}
/***** Tooltips (rich): calendar and Gantt issue hover cards *****/
div.tooltip:hover span.tip {
inline-size: 300px;
background-color: var(--md-sys-color-surface-container);
color: var(--md-sys-color-on-surface-variant);
border: 0;
border-radius: var(--md-sys-shape-corner-medium);
box-shadow: var(--md-sys-elevation-level2);
padding-block: 12px;
padding-inline: 16px;
font: var(--md-sys-typescale-body-medium);
letter-spacing: var(--md-sys-typescale-body-medium-tracking);
}
div.tooltip span.tip strong { color: var(--md-sys-color-on-surface); font-weight: 500; }
div.tooltip span.tip .avatar { vertical-align: middle; }
/* Structured by theme.js (structureTip): title block, then a label/value grid. */
div.tooltip span.nm-tip .nm-tip__title {
display: flex;
flex-direction: column;
gap: 2px;
margin-block-end: 12px;
}
div.tooltip span.nm-tip .nm-tip__title > a {
font: var(--md-sys-typescale-label-medium);
letter-spacing: var(--md-sys-typescale-label-medium-tracking);
text-decoration: none;
}
div.tooltip span.nm-tip .nm-tip__title > span {
color: var(--md-sys-color-on-surface);
font: var(--md-sys-typescale-title-small);
letter-spacing: var(--md-sys-typescale-title-small-tracking);
}
div.tooltip span.nm-tip .nm-tip__fields {
display: grid;
grid-template-columns: auto 1fr;
gap: 4px 16px;
align-items: center;
}
div.tooltip span.nm-tip .nm-tip__fields > strong {
color: var(--md-sys-color-on-surface-variant);
font: var(--md-sys-typescale-label-medium);
letter-spacing: var(--md-sys-typescale-label-medium-tracking);
}
div.tooltip span.nm-tip .nm-tip__fields > span {
color: var(--md-sys-color-on-surface);
display: flex;
align-items: center;
gap: 6px;
min-inline-size: 0;
}
/***** jQuery UI: dialogs, date picker, menus *****/
.ui-widget, .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: var(--md-ref-typeface-plain); }
.ui-widget.ui-widget-content, .ui-widget-content {
background: var(--md-sys-color-surface-container-high);
border-color: var(--md-sys-color-outline-variant);
color: var(--md-sys-color-on-surface);
}
.ui-widget-content a { color: var(--md-sys-color-primary); }
.ui-dialog.ui-widget.ui-widget-content {
padding: 8px;
border: 0;
border-radius: var(--md-sys-shape-corner-extra-large);
box-shadow: var(--md-sys-elevation-level3);
}
.ui-widget-header {
background: transparent;
border: 0;
color: var(--md-sys-color-on-surface);
}
.ui-dialog .ui-dialog-titlebar { padding-block: 16px 8px; padding-inline: 16px; }
.ui-dialog .ui-dialog-title { font: var(--md-sys-typescale-headline-small); }
.ui-dialog .ui-dialog-content { padding-inline: 16px; }
.ui-dialog .ui-dialog-titlebar-close {
inline-size: 40px;
block-size: 40px;
margin-block-start: -20px;
border: 0;
border-radius: var(--md-sys-shape-corner-full);
background: transparent;
}
.ui-widget-overlay { background: var(--md-sys-color-scrim); opacity: 32%; }
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
background: transparent;
border-color: transparent;
color: var(--md-sys-color-on-surface);
border-radius: var(--md-sys-shape-corner-full);
}
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus {
background: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-hover-state-layer-opacity), transparent);
border-color: transparent;
color: var(--md-sys-color-on-surface);
}
.ui-state-highlight, .ui-widget-content .ui-state-highlight {
background: transparent;
border: 1px solid var(--md-sys-color-primary);
color: var(--md-sys-color-primary);
}
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {
background: var(--md-sys-color-primary);
border-color: var(--md-sys-color-primary);
color: var(--md-sys-color-on-primary);
}
.ui-datepicker { padding: 12px; border-radius: var(--md-sys-shape-corner-large); box-shadow: var(--md-sys-elevation-level3); }
.ui-datepicker th { color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-small); }
.ui-datepicker td a, .ui-datepicker td span { text-align: center; padding: 6px; }
.ui-autocomplete, .ui-menu, .tribute-container ul {
background: var(--md-sys-color-surface-container);
border: 0;
border-radius: var(--md-sys-shape-corner-extra-small);
box-shadow: var(--md-sys-elevation-level2);
color: var(--md-sys-color-on-surface);
padding-block: 8px;
}
.ui-menu .ui-menu-item-wrapper.ui-state-active, .tribute-container li.highlight {
margin: 0;
background: var(--md-sys-color-secondary-container);
border-color: transparent;
color: var(--md-sys-color-on-secondary-container);
}
/***** Icons *****/
/* The theme sprite (images/icons.svg) draws Material Symbols with fill="currentColor",
so icon color comes from `color`. Core's `stroke` rules still style plugin icons. */
svg.icon-svg { color: var(--md-sys-color-on-surface-variant); }
a.icon .icon-svg, a.icon-only .icon-svg, span.icon-actions .icon-svg, a .icon-svg { color: var(--md-sys-color-primary); }
a.icon:hover .icon-svg, a.icon-only:hover .icon-svg, span.icon-actions:hover .icon-svg { color: var(--md-sys-color-on-surface); }
.icon-ok svg.icon-svg { color: var(--md-sys-color-success); }
.icon-error svg.icon-svg { color: var(--md-sys-color-error); }
.icon-warning svg.icon-svg { color: var(--md-sys-color-warning); }
div.flash svg.icon-svg, #errorExplanation svg.icon-svg, .conflict svg.icon-svg,
.top-menu__links svg.icon-svg, #account .dropdown-trigger .icon-svg,
#main-menu svg.icon-svg, #sidebar a.selected svg.icon-svg, .drdn-items svg.icon-svg { color: inherit; }
html .context-menu-selection svg.icon-svg { color: var(--md-sys-color-on-secondary-container) !important; }
/***** Wiki toolbar (jstoolbar.css loads after the theme) *****/
/* Core draws the buttons as fixed-color background images, unreadable in dark mode.
The same SVGs are used as masks here, filled with currentColor. */
html .jstElements { block-size: auto; padding-block-end: 4px; }
html .jstElements button {
position: relative;
inline-size: 32px;
block-size: 32px;
margin-inline-end: 0;
padding: 0;
border: 0;
border-radius: var(--md-sys-shape-corner-full);
background-color: transparent;
background-image: none;
color: var(--md-sys-color-on-surface-variant);
opacity: 1;
vertical-align: middle;
}
html .jstElements button:hover { background-color: color-mix(in srgb, currentColor var(--md-sys-state-hover-state-layer-opacity), transparent); color: var(--md-sys-color-on-surface); }
html .jstElements button::after {
content: "";
position: absolute;
inset: 7px;
background-color: currentColor;
mask: var(--nm-jst-icon) center / contain no-repeat;
}
html .jstElements button.jstb_pre::after { display: none; }
html .jstb_pre::before { color: currentColor; font: var(--md-sys-typescale-label-small); }
html .jstSpacer { margin-inline-end: 8px; }
html .jstb_strong { --nm-jst-icon: url(/jstoolbar/bold.svg); }
html .jstb_em { --nm-jst-icon: url(/jstoolbar/italic.svg); }
html .jstb_ins { --nm-jst-icon: url(/jstoolbar/underline.svg); }
html .jstb_del { --nm-jst-icon: url(/jstoolbar/strikethrough.svg); }
html .jstb_code { --nm-jst-icon: url(/jstoolbar/letter-c.svg); }
html .jstb_h1 { --nm-jst-icon: url(/jstoolbar/h1.svg); }
html .jstb_h2 { --nm-jst-icon: url(/jstoolbar/h2.svg); }
html .jstb_h3 { --nm-jst-icon: url(/jstoolbar/h3.svg); }
html .jstb_ul { --nm-jst-icon: url(/jstoolbar/list.svg); }
html .jstb_ol { --nm-jst-icon: url(/jstoolbar/list-numbers.svg); }
html .jstb_tl { --nm-jst-icon: url(/jstoolbar/list-check.svg); }
html .jstb_bq { --nm-jst-icon: url(/jstoolbar/indent-increase.svg); }
html .jstb_unbq { --nm-jst-icon: url(/jstoolbar/indent-decrease.svg); }
html .jstb_precode { --nm-jst-icon: url(/jstoolbar/code.svg); }
html .jstb_link { --nm-jst-icon: url(/jstoolbar/wiki_link.svg); }
html .jstb_img { --nm-jst-icon: url(/jstoolbar/image.svg); }
html .jstb_table { --nm-jst-icon: url(/jstoolbar/table.svg); }
html .jstb_help { --nm-jst-icon: url(/jstoolbar/help.svg); }
html .wiki-preview { background-color: transparent; color: var(--md-sys-color-on-surface); border-color: var(--md-sys-color-outline-variant); border-radius: var(--md-sys-shape-corner-extra-small); }
html .table-generator td { background-color: var(--md-sys-color-surface-container-high); border-color: var(--md-sys-color-outline); }
html .table-generator td.selected-cell, html .table-generator td:hover { background-color: var(--md-sys-color-primary-container); }
/***** Appearance picker (added by javascripts/theme.js to the profile menu and mobile flyout) *****/
.nm-appearance { padding-block: 8px 12px; padding-inline: 12px; }
.nm-appearance__title {
margin-block-end: 8px;
color: var(--md-sys-color-on-surface-variant);
font: var(--md-sys-typescale-label-medium);
letter-spacing: var(--md-sys-typescale-label-medium-tracking);
}
/* M3 segmented button */
.nm-segmented { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; margin-block-end: 12px; } /* equal segments */
.nm-segmented button {
border-radius: 0;
block-size: 32px;
padding-inline: 8px;
border: 1px solid var(--md-sys-color-outline);
background: transparent;
color: var(--md-sys-color-on-surface);
font: var(--md-sys-typescale-label-large);
cursor: pointer;
}
.nm-segmented button + button { margin-inline-start: -1px; }
.nm-segmented button:first-child { border-start-start-radius: var(--md-sys-shape-corner-full); border-end-start-radius: var(--md-sys-shape-corner-full); }
.nm-segmented button:last-child { border-start-end-radius: var(--md-sys-shape-corner-full); border-end-end-radius: var(--md-sys-shape-corner-full); }
.nm-segmented button:hover { background-image: var(--nm-state-hover); }
.nm-segmented button[aria-pressed="true"] { background-color: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); }
/* Color swatches: the selected one gets a ring */
.nm-swatches { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px; }
.nm-swatch {
flex-shrink: 0;
inline-size: 28px;
block-size: 28px;
padding: 0;
border: 0;
border-radius: var(--md-sys-shape-corner-full);
background: var(--nm-swatch);
cursor: pointer;
}
/* Custom color: a native color input stretched invisibly over a rainbow (or the picked color) swatch */
.nm-swatch--custom { position: relative; background: var(--nm-swatch, conic-gradient(#e53935, #fdd835, #43a047, #1e88e5, #8e24aa, #e53935)); }
.nm-swatch--custom input { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; padding: 0; border: 0; opacity: 0; cursor: pointer; }
.nm-swatch--custom:focus-within { outline: 2px solid var(--md-sys-color-primary); outline-offset: 2px; }
/* theme.js lazy-loads the scheme generator from here; Redmine rewrites url() to the digested path */
:root { --nm-scheme-js: url(./scheme.js); }
.nm-swatch[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--md-sys-color-surface-container), 0 0 0 4px var(--md-sys-color-on-surface); }
html .flyout-menu .nm-appearance { padding-inline: 16px; }
html .flyout-menu .nm-appearance__title { color: var(--md-sys-color-on-surface-variant); }
/***** Loading indicator: an M3 snackbar-style chip on inverse surface *****/
#ajax-indicator {
inline-size: auto;
padding-block: 12px;
padding-inline: 16px;
border: 0;
border-radius: var(--md-sys-shape-corner-extra-small);
background-color: var(--md-sys-color-inverse-surface);
color: var(--md-sys-color-inverse-on-surface);
box-shadow: var(--md-sys-elevation-level3);
font: var(--md-sys-typescale-body-medium);
opacity: 1;
}
/***** Code block copy button and dragged table rows *****/
div.pre-wrapper a.copy-pre-content-link {
padding: 4px;
border: 0;
border-radius: var(--md-sys-shape-corner-full);
background-color: var(--md-sys-color-surface-container-high);
color: var(--md-sys-color-on-surface-variant);
}
tr.ui-sortable-helper { border-color: var(--md-sys-color-outline-variant); box-shadow: var(--md-sys-elevation-level2); }