Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 109 additions & 36 deletions assets/css/search.css
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@
box-sizing: border-box;
}

html {
overflow-x: hidden;
width: 100%;
}
/* No overflow-x clip here on purpose. Hiding horizontal overflow on the root
does not remove it, it just makes whatever sits past the edge unreachable --
a worse 1.4.10 outcome than a scrollbar. The widths below are sized so that
nothing overflows down to 320px, so there is nothing to clip. */

a {
color: inherit;
Expand Down Expand Up @@ -123,20 +123,34 @@ header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
/* "Learn@MDL" is one unbreakable token, and at 2.5rem it is wider than a
320px viewport once text is resized to 200%. Breaking it is the lesser
evil: capping the size instead would be the thing 1.4.4 forbids. */
overflow-wrap: break-word;
}

header p {
font-size: 1.1rem;
opacity: 0.9;
}

/* Capped by height on roomy screens, but free to scale down by width once the
viewport is narrower than the lockup. Fixed heights made the UTL logo 313px
wide, which is wider than the 320px reflow target on its own (1.4.10). */
.logo-mdl,
.logo-utl {
width: auto;
height: auto;
max-width: 100%;
}

.logo-mdl {
height: 100px;
max-height: 100px;
margin-bottom: 15px;
}

.logo-utl {
height: 70px;
max-height: 70px;
margin-bottom: 30px;
}

Expand All @@ -151,6 +165,7 @@ header p.header-meta {
align-items: center;
justify-content: center;
gap: 16px;
flex-wrap: wrap;
}

.header-links a {
Expand Down Expand Up @@ -196,10 +211,27 @@ header p.header-meta {
margin-bottom: 20px;
}

/* A control row at every width: the search field takes the slack and the two
buttons keep their intrinsic size. Wraps rather than overflows, so the row
still fits a 320px viewport (1.4.10) and still fits once the labels grow at
200% text (1.4.4). Bottom-aligned so the buttons line up with the input
rather than with the label above it. */
.sticky-search-container {
max-width: 600px;
margin: 0 auto;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
gap: 10px;
}

/* Small basis on purpose: the row has to stay on one line down to 320px, or
the pinned bar doubles in height and swallows a 256px-tall viewport. The
field gives up width to the buttons rather than pushing them to a new row. */
.search-box {
flex: 1 1 120px;
min-width: 0;
}

.main-content {
Expand Down Expand Up @@ -475,13 +507,18 @@ header p.header-meta {
flex-wrap: wrap;
}

/* Each label-and-select pair wraps internally before the row does, so at 320px
or at 200% text the label stacks over its control instead of pushing the
results panel wider than the viewport (1.4.10, 1.4.4) */
.per-page-selector,
.sort-options {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: var(--text-muted);
flex-wrap: wrap;
min-width: 0;
}

.per-page-selector select,
Expand All @@ -493,29 +530,34 @@ header p.header-meta {
color: var(--text-body);
cursor: pointer;
background: var(--surface);
max-width: 100%;
}

/* Caps the column count without forcing it. Each track's floor is whichever
is larger: 240px, or the width one of --max-cards-per-row columns would get.
So the grid never exceeds that many columns, and drops to fewer once the
panel is too narrow to give each card 240px -- which is what happens at high
zoom. The previous rule pinned the count from 481px up, which at 200% zoom
left three ~170px columns breaking titles one word per line (1.4.10). */
.guides-grid {
--card-gap: 20px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
grid-template-columns: repeat(
auto-fit,
minmax(
max(
240px,
(100% - (var(--max-cards-per-row) - 1) * var(--card-gap))
/ var(--max-cards-per-row)
),
1fr
)
);
grid-auto-columns: 1fr;
gap: 20px;
gap: var(--card-gap);
margin-bottom: 30px;
}

/* Limit maximum number of columns */
@media (min-width: 481px) {
.guides-grid {
grid-template-columns: repeat(var(--max-cards-per-row), 1fr);
}
}

@media (max-width: 480px) {
.guides-grid {
grid-template-columns: 1fr;
}
}

.guides-card {
border-radius: 10px;
padding: 20px;
Expand Down Expand Up @@ -809,6 +851,14 @@ header p.header-meta {
margin-bottom: 10px;
}

/* Floats bottom-right, which means it can sit on top of content. Two rules
keep that from hiding anything: --back-to-top-clearance reserves room below
the page and past every focus target, and the button is dropped entirely at
high zoom, where it used to land on the sort control (1.4.10, 2.4.11). */
:root {
--back-to-top-clearance: 100px; /* 40px offset + 50px button + 10px */
}

#back-to-top {
position: fixed;
bottom: 40px;
Expand Down Expand Up @@ -841,6 +891,11 @@ header p.header-meta {
background-color: var(--surface-subtle);
}

/* The last card can scroll clear of the button */
body {
padding-bottom: max(20px, var(--back-to-top-clearance));
}

.visually-hidden {
position: absolute;
width: 1px;
Expand Down Expand Up @@ -877,6 +932,8 @@ header p.header-meta {
#results,
.results-section :is(a, button, input, select, [tabindex]) {
scroll-margin-top: calc(var(--sticky-search-h) + 10px);
/* ...and the floating Back to top below it */
scroll-margin-bottom: var(--back-to-top-clearance);
}

.section-heading:focus,
Expand All @@ -895,19 +952,6 @@ header p.header-meta {
grid-template-columns: 1fr;
}

/* Search field and Filters share one row, bottom-aligned so the button
lines up with the input rather than with the label above it */
.sticky-search-container {
display: flex;
align-items: flex-end;
gap: 10px;
}

.search-box {
flex: 1;
min-width: 0;
}

.filter-toggle {
display: inline-flex;
align-items: center;
Expand Down Expand Up @@ -1004,26 +1048,36 @@ header p.header-meta {

@media (max-width: 768px) {
body {
padding: 8px;
padding: 8px 8px max(8px, var(--back-to-top-clearance));
}

.container {
padding: 0;
}

.guides-grid {
gap: 15px;
--card-gap: 15px;
}

.results-controls {
width: 100%;
justify-content: space-between;
/* Below the width where the two groups fit side by side they stack,
rather than the row forcing a horizontal scrollbar */
gap: 10px 15px;
}

.pagination {
flex-wrap: wrap;
}

/* Trimmed to match the shorter input at this size, still past the 44px
target floor */
.filter-toggle {
height: 48px;
min-height: 48px;
}

#back-to-top {
bottom: 20px;
right: 20px;
Expand All @@ -1036,6 +1090,10 @@ header p.header-meta {
height: 20px;
}

:root {
--back-to-top-clearance: 75px; /* 20px + 45px + 10px */
}

header h1 {
font-size: 2rem;
}
Expand Down Expand Up @@ -1068,6 +1126,21 @@ header p.header-meta {
padding: 10px 0;
}
}
/* 480px wide is 400% zoom on a 1280px screen (or a phone); 500px tall is 200%
on a 720px-tall one. There the button would cover controls, so it goes. Home
still jumps to the top, and the search bar is pinned there anyway. Sits
after the 768px block so its zero clearance wins over the 75px there. */
@media (max-width: 480px), (max-height: 500px) {
#back-to-top,
#back-to-top.show {
display: none;
}

:root {
--back-to-top-clearance: 0px;
}
}

@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
transition-property: opacity, visibility, background-color, color, border-color, box-shadow !important;
Expand Down
Loading