From 900px up, selects and text fields fill their column up to 480px, numbers and dates are 140px, and long text stays full width, so every form shares one right edge. Below 900px every field runs full width. Overrides core's id-pinned widths (% Done, mobile dates, settings textareas). check-form-alignment.mjs now checks widths at 1440, 1024 and 390px across all settings tabs and admin forms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
269 lines
14 KiB
CSS
269 lines
14 KiB
CSS
/*
|
|
* Mobile overrides at core's responsive.css breakpoint. The core file stays in place
|
|
* (a theme file named responsive.css would replace it); it loads after the theme,
|
|
* hence the `html` prefix on conflicting selectors.
|
|
*/
|
|
|
|
@media screen and (max-width: 899px) {
|
|
/* Top app bar */
|
|
html #header { background-color: var(--md-sys-color-surface-container); color: var(--md-sys-color-on-surface); }
|
|
html #header a.mobile-toggle-button { color: var(--md-sys-color-on-surface-variant); border-inline-start: 0; }
|
|
html #project-jump .drdn-trigger {
|
|
border: 0;
|
|
color: var(--md-sys-color-on-surface);
|
|
font: var(--md-sys-typescale-title-large);
|
|
line-height: 50px;
|
|
}
|
|
html #project-jump.drdn { padding-inline-start: 8px; }
|
|
/* Header icons: Material Symbols masks instead of core's scaled "^" and "≡" text glyphs */
|
|
html #project-jump .drdn-trigger:before {
|
|
content: '';
|
|
inset-block: 0;
|
|
margin-block: auto;
|
|
inline-size: 24px;
|
|
block-size: 24px;
|
|
padding: 0;
|
|
transform: none;
|
|
opacity: 1;
|
|
background-color: var(--md-sys-color-on-surface-variant);
|
|
mask: url(../images/arrow-drop-down.svg) center / 24px no-repeat;
|
|
}
|
|
html #header a.mobile-toggle-button {
|
|
inline-size: 48px;
|
|
block-size: 48px;
|
|
margin-block-start: 8px;
|
|
margin-inline-end: 8px;
|
|
border-radius: var(--md-sys-shape-corner-full);
|
|
line-height: normal;
|
|
}
|
|
html #header a.mobile-toggle-button:hover { background-image: var(--nm-state-hover); }
|
|
html .mobile-toggle-button:after {
|
|
content: '';
|
|
inline-size: 24px;
|
|
block-size: 24px;
|
|
margin: 12px;
|
|
background-color: currentColor;
|
|
mask: url(../images/menu.svg) center / 24px no-repeat;
|
|
}
|
|
|
|
/* Flyout: M3 modal navigation drawer. It slides over the page behind a scrim instead of
|
|
core's push, which shoves page and header off screen. Tapping the scrim hits #main,
|
|
which core's responsive.js already binds to close the flyout. */
|
|
html.flyout-is-active :is(#wrapper, #header) { inset-inline-end: 0; }
|
|
html .flyout-menu {
|
|
--nm-drawer-width: min(360px, calc(100vw - 56px)); /* M3 modal drawer; core's 250px squeezes the appearance picker */
|
|
position: fixed;
|
|
inset-block: 0;
|
|
inset-inline-end: calc(-1 * var(--nm-drawer-width));
|
|
inline-size: var(--nm-drawer-width);
|
|
z-index: 10001; /* over core's fixed header (9999) and the scrim */
|
|
block-size: auto;
|
|
overflow-y: auto;
|
|
overscroll-behavior: contain;
|
|
visibility: hidden;
|
|
transition: inset-inline-end 250ms cubic-bezier(0.2, 0, 0, 1), visibility 250ms;
|
|
border-start-start-radius: var(--md-sys-shape-corner-large);
|
|
border-end-start-radius: var(--md-sys-shape-corner-large);
|
|
box-shadow: var(--md-sys-elevation-level1);
|
|
background-color: var(--md-sys-color-surface-container-low);
|
|
color: var(--md-sys-color-on-surface);
|
|
padding-inline: 12px;
|
|
box-sizing: border-box;
|
|
}
|
|
html.flyout-is-active .flyout-menu { inset-inline-end: 0; visibility: visible; }
|
|
html.flyout-is-active #main::after {
|
|
content: '';
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 10000;
|
|
background-color: color-mix(in srgb, var(--md-sys-color-scrim) 32%, transparent);
|
|
}
|
|
html .flyout-menu h3 {
|
|
block-size: auto;
|
|
margin-block: 16px 4px;
|
|
padding-inline: 16px;
|
|
border: 0;
|
|
background-color: transparent;
|
|
color: var(--md-sys-color-on-surface-variant);
|
|
font: var(--md-sys-typescale-title-small);
|
|
letter-spacing: var(--md-sys-typescale-title-small-tracking);
|
|
text-transform: none;
|
|
}
|
|
/* M3 drawer dividers between groups; headings alone look like one more nav item */
|
|
html .flyout-menu > :is(h3, .flyout-menu__sidebar:has(#sidebar-wrapper > *), .nm-appearance) {
|
|
display: block; /* the sidebar group is a span */
|
|
margin-block-start: 8px;
|
|
padding-block-start: 8px;
|
|
border-block-start: 1px solid var(--md-sys-color-outline-variant);
|
|
}
|
|
html .flyout-menu > h3 { padding-block-start: 16px; }
|
|
/* Sidebar forms (e.g. activity filters) line up with the nav labels; a field stacks under
|
|
its label, which is a bare text node, so grid is the only way to put it on its own row */
|
|
html .flyout-menu__sidebar :is(form > p, li:has(> input[type="checkbox"])) { padding-inline: 16px; }
|
|
html .flyout-menu__sidebar p:has(> :is(select, input:not([type="submit"], [type="checkbox"], [type="radio"]))) {
|
|
display: grid;
|
|
gap: 4px;
|
|
color: var(--md-sys-color-on-surface-variant);
|
|
font: var(--md-sys-typescale-label-large);
|
|
}
|
|
html .flyout-menu__sidebar p > :is(select, input:not([type="submit"], [type="checkbox"], [type="radio"])) { inline-size: 100%; box-sizing: border-box; }
|
|
html .flyout-menu__sidebar li:has(> input[type="checkbox"]) { display: flex; align-items: center; gap: 12px; min-block-size: 40px; border: 0; }
|
|
html .flyout-menu .flyout-menu__sidebar li:has(> input[type="checkbox"]) a { block-size: auto; padding: 0; line-height: inherit; }
|
|
html .flyout-menu h4 { color: var(--md-sys-color-on-surface); }
|
|
html .flyout-menu a { color: var(--md-sys-color-on-surface-variant); }
|
|
html .flyout-menu ul li a, html .flyout-menu ul li:first-child a {
|
|
block-size: 48px;
|
|
line-height: 48px;
|
|
margin-inline-start: 0;
|
|
padding-inline: 16px;
|
|
border: 0;
|
|
border-radius: var(--md-sys-shape-corner-full);
|
|
font: var(--md-sys-typescale-label-large);
|
|
line-height: 48px;
|
|
}
|
|
html .flyout-menu ul li a:hover { background-image: var(--nm-state-hover); }
|
|
html .flyout-menu ul li a.selected {
|
|
background-color: var(--md-sys-color-secondary-container);
|
|
color: var(--md-sys-color-on-secondary-container);
|
|
}
|
|
html .flyout-menu #watchers ul li, html .flyout-menu ul.queries li, html .flyout-menu__avatar { border-block-start: 0; }
|
|
html .flyout-menu .icon svg, html .flyout-menu .icon-only svg { color: inherit; stroke: currentColor; }
|
|
html .flyout-menu__search input[type='text'] {
|
|
block-size: 48px;
|
|
border-radius: var(--md-sys-shape-corner-full);
|
|
background-color: var(--md-sys-color-surface-container-highest);
|
|
color: var(--md-sys-color-on-surface);
|
|
padding-inline-start: 52px;
|
|
}
|
|
/* Search pill, avatar row and nav labels share one inline start: the icon and the
|
|
avatar sit where the nav labels begin (drawer padding 12px + item padding 16px) */
|
|
html .flyout-menu .flyout-menu__search { padding-inline: 0; }
|
|
html .search-magnifier--flyout { inset-inline-start: 28px; }
|
|
html .flyout-menu .flyout-menu__avatar { padding-inline-start: 16px; }
|
|
|
|
/* Calendar month bar: the month select fills the row, Apply / Clear / Save wrap below */
|
|
html body.controller-calendars p.buttons select#month { flex: 1 1 0; min-inline-size: 0; }
|
|
html body.controller-calendars #query_form_with_buttons::after { content: ''; order: 2; flex-basis: 100%; margin-block: -4px; } /* line break */
|
|
html body.controller-calendars p.buttons a { order: 3; }
|
|
|
|
/* Calendar as an agenda: weekday column on the left, issues on the right. Days of the
|
|
neighbouring months are dropped; empty days shrink to one line. */
|
|
html .cal .week-number {
|
|
padding-block: 8px;
|
|
padding-inline: 16px;
|
|
border: 0;
|
|
border-block-start: 1px solid var(--md-sys-color-outline-variant);
|
|
background-color: var(--md-sys-color-surface-container);
|
|
color: var(--md-sys-color-on-surface-variant);
|
|
font: var(--md-sys-typescale-label-medium);
|
|
letter-spacing: var(--md-sys-typescale-label-medium-tracking);
|
|
}
|
|
html .cal .week-number:first-child { border-block-start: 0; }
|
|
html .cal .calbody.other-month { display: none; }
|
|
html .cal .calbody {
|
|
display: grid;
|
|
grid-template-columns: 40px minmax(0, 1fr);
|
|
column-gap: 8px;
|
|
align-items: start;
|
|
min-block-size: 0;
|
|
padding-block: 8px;
|
|
padding-inline: 8px;
|
|
border: 0;
|
|
border-block-start: 1px solid var(--md-sys-color-outline-variant);
|
|
}
|
|
/* ponytail: the date spans 50 implicit rows (empty ones collapse to 0); a day with more
|
|
issues lets the extra ones fall under the date */
|
|
html .cal .calbody p.day-num {
|
|
grid-row: 1 / span 50;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
margin: 0;
|
|
text-align: center;
|
|
}
|
|
html .cal .calbody .day-value { inline-size: 32px; block-size: 32px; font: var(--md-sys-typescale-title-medium); }
|
|
html .cal .calbody .abbr-day { color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-label-small); }
|
|
html .cal .calbody div.issue, html .cal .calbody > .icon { grid-column: 2; margin-block: 0 4px; }
|
|
/* An empty day is one short line: date and weekday side by side, greyed out */
|
|
html .cal .calbody:not(:has(div.issue, > .icon)) { padding-block: 4px; }
|
|
html .cal .calbody:not(:has(div.issue, > .icon)) p.day-num { flex-direction: row; gap: 8px; color: var(--md-sys-color-on-surface-variant); }
|
|
html .cal .calbody:not(:has(div.issue, > .icon)) .day-value { flex: none; inline-size: 40px; block-size: 24px; font: var(--md-sys-typescale-label-large); }
|
|
/* Today: tinted row with a primary stripe on its leading edge */
|
|
html .cal .calbody.today {
|
|
border-inline-start: 4px solid var(--md-sys-color-primary);
|
|
padding-inline-start: 4px;
|
|
background-color: color-mix(in srgb, var(--md-sys-color-primary) 8%, var(--md-sys-color-surface));
|
|
}
|
|
/* Page actions become M3 outlined buttons, like Apply / Clear. The forum topic wraps its
|
|
actions in a quote-reply controller, so core's #content > .contextual misses them. */
|
|
html #content > [data-controller="quote-reply"] > .contextual {
|
|
inline-size: 100%;
|
|
margin-block-end: 8px;
|
|
padding-inline-start: 0;
|
|
white-space: normal;
|
|
}
|
|
html :is(#content > .contextual > a, #content > .contextual .drdn, #content > [data-controller="quote-reply"] > .contextual > a, p.buttons a) {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
block-size: 40px;
|
|
margin-block: 4px;
|
|
margin-inline: 0 4px;
|
|
padding-block: 0;
|
|
padding-inline: 16px;
|
|
border: 1px solid var(--md-sys-color-outline);
|
|
border-radius: var(--md-sys-shape-corner-full);
|
|
box-sizing: border-box;
|
|
font: var(--md-sys-typescale-label-large);
|
|
letter-spacing: var(--md-sys-typescale-label-large-tracking);
|
|
}
|
|
|
|
/* A scrolling table takes its natural width instead of squeezing text columns to a
|
|
word per line; it scrolls inside its card */
|
|
html .autoscroll > table.list { inline-size: max-content; min-inline-size: 100%; }
|
|
/* Tables core does not wrap scroll themselves, so they no longer push the whole content
|
|
area sideways; thead and tbody share one anonymous table, so columns stay aligned.
|
|
ponytail: a table narrower than the screen would leave a gap inside its border, so small
|
|
summary tables are excluded by class; add others here if one shows a gap */
|
|
html #content table.list:not(.autoscroll > table, .issue-report) { display: block; overflow-x: auto; max-inline-size: 100%; }
|
|
|
|
/* Form fields run full width; a select keeps room for the icon button after it */
|
|
html form .attributes select { inline-size: 100%; }
|
|
html form .attributes select:has(+ .icon-only) { inline-size: calc(100% - 36px); }
|
|
/* Core leaves the tracker at 90%; only the project row shares its line (with "Private") */
|
|
html #all_attributes #issue_tracker_id { inline-size: 100%; }
|
|
/* Core leaves dates at their content width; every field runs full width here */
|
|
html .tabular input:is(.date, [type="date"]) { inline-size: 100%; max-inline-size: 100%; }
|
|
html .tabular input[type="radio"] { inline-size: auto; }
|
|
|
|
/* Query filters: operator and values run full width under the checkbox label instead of
|
|
the desktop's fixed 180px / 260px columns. A flex-basis of 0 overrides those widths, so
|
|
"between" fields split the row and a multi-select toggle keeps its spot after the field. */
|
|
html #filters-table .filter { row-gap: 8px; margin-block-end: 8px; }
|
|
html #filters-table .filter :is(.operator, .values) { flex: 1 1 100%; }
|
|
html #filters-table .filter .values:not(:has(> span:not([style*="none"]))) { display: none; } /* e.g. status "open" */
|
|
html #filters-table .filter .operator select { inline-size: 100%; }
|
|
html #filters-table .filter .values > span { display: flex; flex: 1 1 0; align-items: center; gap: 8px; }
|
|
html #filters-table .filter .values .value:not([size="3"]) { flex: 1 1 0; min-inline-size: 0; }
|
|
html .add-filter { justify-content: stretch; margin-block-start: 16px; } /* full-width button */
|
|
|
|
/* Wiki toolbar: buttons wrap instead of being cut off */
|
|
html #content .jstTabs.tabs { clear: both; block-size: auto; overflow: visible; } /* below the floated field label */
|
|
html #content .jstTabs.tabs ul { position: static; display: flex; flex-wrap: wrap; inline-size: auto; min-inline-size: 0; }
|
|
html #content .jstTabs.tabs li.tab-elements { flex: 1 1 auto; min-inline-size: 0; block-size: auto; }
|
|
html #content .jstTabs .jstElements { display: flex; flex-wrap: wrap; white-space: normal; }
|
|
html #content .jstTabs.tabs li.tab-elements::before { display: none; } /* core's full-height strut for vertical centring */
|
|
|
|
/* Subtasks and related issues: the progress bar fits its cell, the subject leaves room
|
|
for both icon buttons */
|
|
html :is(#issue_tree, #relations) td.done_ratio table.progress { inline-size: 100%; }
|
|
html :is(#issue_tree, #relations):not(.with-related-issues-table-headers) .issue:has(.buttons a) > td.subject { padding-inline-end: 72px; }
|
|
|
|
html div#version-summary { margin-block-start: 16px; }
|
|
|
|
/* Core gives the current, previous and next page a third of the row each */
|
|
html .pagination ul.pages li:is(.current, .previous, .next) { inline-size: auto; overflow: visible; }
|
|
|
|
/* The desktop sidebar card has no place on mobile; its content moves into the flyout */
|
|
#sidebar { margin: 0; border-radius: 0; }
|
|
}
|