max / makenotwork
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
14 files changed,
+161 insertions,
-55 deletions
| @@ -45,6 +45,7 @@ | |||
| 45 | 45 | # Generated template partials (build.rs output) | |
| 46 | 46 | server/templates/_head_assets.html | |
| 47 | 47 | server/templates/_island.html | |
| 48 | + | server/templates/_sheet.html | |
| 48 | 49 | ||
| 49 | 50 | # Generated rustdoc output | |
| 50 | 51 | server/rustdoc-out/ |
| @@ -5205,6 +5205,7 @@ | |||
| 5205 | 5205 | "log", | |
| 5206 | 5206 | "makeover", | |
| 5207 | 5207 | "makeover-build", | |
| 5208 | + | "makeover-geometry", | |
| 5208 | 5209 | "memmap2", | |
| 5209 | 5210 | "metrics", | |
| 5210 | 5211 | "metrics-exporter-prometheus", |
| @@ -174,6 +174,10 @@ | |||
| 174 | 174 | # (makeover-webview). The same generator GO and BB run; only the output paths | |
| 175 | 175 | # differ, since the server serves its stylesheets rather than bundling them. | |
| 176 | 176 | makeover-build = "0.7.0" | |
| 177 | + | # Read directly for SizeClass, which the breakpoint guard in build.rs compares | |
| 178 | + | # the stylesheets against. makeover-build does not re-export it, so the pin | |
| 179 | + | # lives here and has to track the one makeover-build resolves. | |
| 180 | + | makeover-geometry = "0.6" | |
| 177 | 181 | ||
| 178 | 182 | [dev-dependencies] | |
| 179 | 183 | tower = { version = "0.5.3", features = ["util"] } |
| @@ -35,12 +35,19 @@ | |||
| 35 | 35 | makeover_build::layout_css("static/layout.css", &makeover_build::Emit::default()); | |
| 36 | 36 | println!("cargo::rerun-if-changed=build.rs"); | |
| 37 | 37 | ||
| 38 | + | check_breakpoints(); | |
| 39 | + | ||
| 38 | 40 | // --- Static asset fingerprinting --- | |
| 39 | 41 | // Hash the content of key static files to produce a version suffix. | |
| 40 | 42 | // When any watched file changes, URLs in templates get a new ?v= param, | |
| 41 | 43 | // busting browser caches automatically. | |
| 42 | 44 | let static_files = [ | |
| 43 | 45 | "static/style.css", | |
| 46 | + | // The two per-page sheets. Linked from page templates rather than from | |
| 47 | + | // _head_assets.html, which is why they were outside the fingerprint | |
| 48 | + | // and served stale to any browser holding a cached copy. | |
| 49 | + | "static/wizard.css", | |
| 50 | + | "static/media-player.css", | |
| 44 | 51 | "static/htmx.min.js", | |
| 45 | 52 | "static/upload.js", | |
| 46 | 53 | "static/passkey.js", | |
| @@ -111,6 +118,108 @@ | |||
| 111 | 118 | "# | |
| 112 | 119 | .replace("__VER__", version); | |
| 113 | 120 | write_if_changed(Path::new("templates/_island.html"), &island_partial); | |
| 121 | + | ||
| 122 | + | // Per-page stylesheet loader, same idea as the island macro. wizard.css and | |
| 123 | + | // media-player.css are linked by the pages that need them rather than by | |
| 124 | + | // _head_assets.html, so this is how they get the content hash. | |
| 125 | + | let sheet_partial = r#"{% macro sheet(name) -%} | |
| 126 | + | <link rel="stylesheet" href="/static/{{ name }}?v=__VER__"> | |
| 127 | + | {%- endmacro %} | |
| 128 | + | "# | |
| 129 | + | .replace("__VER__", version); | |
| 130 | + | write_if_changed(Path::new("templates/_sheet.html"), &sheet_partial); | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | /// The hand-written stylesheets. Ordered, so the guard reports the same way | |
| 134 | + | /// twice. `geometry.css` and `layout.css` are excluded: they are generated. | |
| 135 | + | const HAND_WRITTEN_CSS: [&str; 3] = [ | |
| 136 | + | "static/style.css", | |
| 137 | + | "static/wizard.css", | |
| 138 | + | "static/media-player.css", | |
| 139 | + | ]; | |
| 140 | + | ||
| 141 | + | /// Fail the build on any width breakpoint that is not a `SizeClass` boundary. | |
| 142 | + | /// | |
| 143 | + | /// A media condition cannot read a custom property and `@custom-media` has | |
| 144 | + | /// shipped nowhere, so every threshold in the stylesheets is a hand-typed | |
| 145 | + | /// literal and there is no generator path. The guard is the substitute: bump | |
| 146 | + | /// makeover-geometry to a release that moves a boundary and the build breaks | |
| 147 | + | /// here, rather than the layout breaking quietly in a browser. | |
| 148 | + | /// | |
| 149 | + | /// Only the numbers are checked, not the surrounding syntax. That accepts | |
| 150 | + | /// `(min-width: 600px) and (max-width: 839px)` without having to parse it, and | |
| 151 | + | /// still catches the thing worth catching: a number nobody can trace to the | |
| 152 | + | /// scale. | |
| 153 | + | fn check_breakpoints() { | |
| 154 | + | use makeover_geometry::SizeClass; | |
| 155 | + | ||
| 156 | + | let compact_max = SizeClass::Medium.min_px() - 1; | |
| 157 | + | let expanded_min = SizeClass::Expanded.min_px(); | |
| 158 | + | let allowed = [ | |
| 159 | + | compact_max, | |
| 160 | + | SizeClass::Medium.min_px(), | |
| 161 | + | expanded_min - 1, | |
| 162 | + | expanded_min, | |
| 163 | + | ]; | |
| 164 | + | ||
| 165 | + | let mut strays: Vec<String> = Vec::new(); | |
| 166 | + | for path in HAND_WRITTEN_CSS { | |
| 167 | + | println!("cargo::rerun-if-changed={path}"); | |
| 168 | + | let Ok(css) = fs::read_to_string(path) else { | |
| 169 | + | continue; | |
| 170 | + | }; | |
| 171 | + | for (n, line) in css.lines().enumerate() { | |
| 172 | + | for px in width_conditions(line) { | |
| 173 | + | if !allowed.contains(&px) { | |
| 174 | + | strays.push(format!("{path}:{}: (…-width: {px}px)", n + 1)); | |
| 175 | + | } | |
| 176 | + | } | |
| 177 | + | } | |
| 178 | + | } | |
| 179 | + | ||
| 180 | + | assert!( | |
| 181 | + | strays.is_empty(), | |
| 182 | + | "stylesheet width breakpoints that are not SizeClass boundaries \ | |
| 183 | + | ({}, {}, {}, {}px):\n {}\n\ | |
| 184 | + | Either move the rule to a boundary, or make it dimensional so it \ | |
| 185 | + | needs no threshold at all: a grid wants \ | |
| 186 | + | repeat(auto-fit, minmax(<content floor>, 1fr)) and a size wants \ | |
| 187 | + | clamp(). A threshold is for what appears and disappears.", | |
| 188 | + | allowed[0], | |
| 189 | + | allowed[1], | |
| 190 | + | allowed[2], | |
| 191 | + | allowed[3], | |
| 192 | + | strays.join("\n ") | |
| 193 | + | ); | |
| 194 | + | } | |
| 195 | + | ||
| 196 | + | /// Every pixel value used as a `min-width` or `max-width` media feature on one | |
| 197 | + | /// line. Deliberately narrow: it reads `width` features and ignores the | |
| 198 | + | /// `width` property, `min-width`/`max-width` declarations, and every other | |
| 199 | + | /// number in the sheet. | |
| 200 | + | fn width_conditions(line: &str) -> Vec<u16> { | |
| 201 | + | let mut found = Vec::new(); | |
| 202 | + | for (i, _) in line.match_indices("-width:") { | |
| 203 | + | let prefix = &line[..i]; | |
| 204 | + | if !(prefix.ends_with("min") || prefix.ends_with("max")) { | |
| 205 | + | continue; | |
| 206 | + | } | |
| 207 | + | // A media feature is parenthesised; the property form never is. | |
| 208 | + | let opened = prefix.trim_end_matches(['m', 'i', 'n', 'a', 'x']); | |
| 209 | + | if !opened.ends_with('(') { | |
| 210 | + | continue; | |
| 211 | + | } | |
| 212 | + | let rest = &line[i + "-width:".len()..]; | |
| 213 | + | let digits: String = rest | |
| 214 | + | .trim_start() | |
| 215 | + | .chars() | |
| 216 | + | .take_while(char::is_ascii_digit) | |
| 217 | + | .collect(); | |
| 218 | + | if let Ok(px) = digits.parse::<u16>() { | |
| 219 | + | found.push(px); | |
| 220 | + | } | |
| 221 | + | } | |
| 222 | + | found | |
| 114 | 223 | } | |
| 115 | 224 | ||
| 116 | 225 | /// Write `contents` to `path` only if it differs, to avoid needless rebuilds. |
| @@ -388,7 +388,7 @@ | |||
| 388 | 388 | } | |
| 389 | 389 | ||
| 390 | 390 | /* Responsive */ | |
| 391 | - | @media (max-width: 600px) { | |
| 391 | + | @media (max-width: 599px) { | |
| 392 | 392 | .media-title { | |
| 393 | 393 | font-size: var(--text-title); | |
| 394 | 394 | } |
| @@ -1705,7 +1705,7 @@ | |||
| 1705 | 1705 | ||
| 1706 | 1706 | .item-page .features-grid { | |
| 1707 | 1707 | display: grid; | |
| 1708 | - | grid-template-columns: repeat(2, 1fr); | |
| 1708 | + | grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); | |
| 1709 | 1709 | gap: var(--gap-pane); | |
| 1710 | 1710 | } | |
| 1711 | 1711 | .item-page .version-number { font-size: var(--text-lead); } | |
| @@ -1720,12 +1720,11 @@ | |||
| 1720 | 1720 | ||
| 1721 | 1721 | .item-page .item-footer a { color: var(--content); } | |
| 1722 | 1722 | ||
| 1723 | - | @media (max-width: 768px) { | |
| 1723 | + | @media (max-width: 839px) { | |
| 1724 | 1724 | .item-page .item-layout { grid-template-columns: 1fr; } | |
| 1725 | - | .item-page .features-grid { grid-template-columns: 1fr; } | |
| 1726 | 1725 | } | |
| 1727 | 1726 | ||
| 1728 | - | @media (max-width: 480px) { | |
| 1727 | + | @media (max-width: 599px) { | |
| 1729 | 1728 | .item-page .item-title { font-size: var(--text-head); } | |
| 1730 | 1729 | .item-page .item-price { font-size: var(--text-title); } | |
| 1731 | 1730 | .item-page .item-meta { grid-template-columns: 1fr; gap: var(--gap-peer); } | |
| @@ -1900,12 +1899,10 @@ | |||
| 1900 | 1899 | opacity: 0.7; | |
| 1901 | 1900 | } | |
| 1902 | 1901 | ||
| 1903 | - | @media (max-width: 480px) { | |
| 1902 | + | @media (max-width: 599px) { | |
| 1904 | 1903 | .project-page .store-title { font-size: var(--text-title); } | |
| 1905 | - | .project-page .items-grid { grid-template-columns: 1fr; } | |
| 1906 | 1904 | .project-page a.item-thumbnail { height: 200px; } | |
| 1907 | 1905 | .project-page .store-description { font-size: var(--text-body); } | |
| 1908 | - | .project-page .tiers-grid { grid-template-columns: 1fr; } | |
| 1909 | 1906 | } | |
| 1910 | 1907 | ||
| 1911 | 1908 | /* Library downloads page (templates/pages/library_downloads.html). | |
| @@ -2050,7 +2047,7 @@ | |||
| 2050 | 2047 | ||
| 2051 | 2048 | .library-page .item-footer a { color: var(--content); } | |
| 2052 | 2049 | ||
| 2053 | - | @media (max-width: 600px) { | |
| 2050 | + | @media (max-width: 599px) { | |
| 2054 | 2051 | .library-page .library-header { grid-template-columns: 1fr; } | |
| 2055 | 2052 | .library-page .library-cover img { max-width: 200px; } | |
| 2056 | 2053 | } | |
| @@ -2290,7 +2287,7 @@ | |||
| 2290 | 2287 | .article-page .blog-nav a { color: var(--content); text-decoration: none; } | |
| 2291 | 2288 | .article-page .blog-nav a:hover { text-decoration: underline; } | |
| 2292 | 2289 | ||
| 2293 | - | @media (max-width: 600px) { | |
| 2290 | + | @media (max-width: 599px) { | |
| 2294 | 2291 | .article-page .article-title { font-size: var(--text-title); } | |
| 2295 | 2292 | .article-page .article-deck { font-size: var(--text-lead); } | |
| 2296 | 2293 | .article-page .article-body { font-size: var(--text-body); } | |
| @@ -3309,7 +3306,7 @@ | |||
| 3309 | 3306 | ||
| 3310 | 3307 | .purchase-page .checkout-footer a { color: var(--content); } | |
| 3311 | 3308 | ||
| 3312 | - | @media (max-width: 480px) { | |
| 3309 | + | @media (max-width: 599px) { | |
| 3313 | 3310 | .purchase-page .container { padding: 0 var(--gap-section); } | |
| 3314 | 3311 | .purchase-page .item-summary { flex-direction: column; } | |
| 3315 | 3312 | .purchase-page .item-thumbnail { width: 100%; height: 160px; } | |
| @@ -3414,7 +3411,7 @@ | |||
| 3414 | 3411 | ||
| 3415 | 3412 | .feed-page .pagination a:hover { background: var(--surface-sunken); } | |
| 3416 | 3413 | ||
| 3417 | - | @media (max-width: 600px) { | |
| 3414 | + | @media (max-width: 599px) { | |
| 3418 | 3415 | .feed-page .table-header, | |
| 3419 | 3416 | .feed-page .table-row { grid-template-columns: 1fr 70px; } | |
| 3420 | 3417 | .feed-page .table-header span:nth-child(1), | |
| @@ -3786,7 +3783,7 @@ | |||
| 3786 | 3783 | .settings-nav a:hover { opacity: 1; } | |
| 3787 | 3784 | .settings-nav a.is-selected { opacity: 1; background: var(--surface-sunken); } | |
| 3788 | 3785 | .settings-body { flex: 1; min-width: 0; } | |
| 3789 | - | @media (max-width: 768px) { | |
| 3786 | + | @media (max-width: 839px) { | |
| 3790 | 3787 | .settings-layout { flex-direction: column; gap: var(--gap-section); } | |
| 3791 | 3788 | .settings-nav { display: flex; flex-wrap: wrap; gap: 0; min-width: 0; } | |
| 3792 | 3789 | .settings-nav a { padding: var(--gap-peer) var(--gap-group); font-size: var(--text-note); } | |
| @@ -3851,7 +3848,7 @@ | |||
| 3851 | 3848 | border-color: var(--primary-dark); | |
| 3852 | 3849 | } | |
| 3853 | 3850 | .library-page .feed-pagination a:hover { background: var(--surface-sunken); } | |
| 3854 | - | @media (max-width: 600px) { | |
| 3851 | + | @media (max-width: 599px) { | |
| 3855 | 3852 | .library-page .feed-table-header, | |
| 3856 | 3853 | .library-page .feed-table-row { | |
| 3857 | 3854 | grid-template-columns: 1fr 70px; | |
| @@ -3906,7 +3903,7 @@ | |||
| 3906 | 3903 | padding: var(--gap-peer) var(--gap-section); | |
| 3907 | 3904 | font-size: var(--text-note); | |
| 3908 | 3905 | } | |
| 3909 | - | @media (max-width: 768px) { | |
| 3906 | + | @media (max-width: 839px) { | |
| 3910 | 3907 | .dashboard-user-page .project-card { flex-direction: column; } | |
| 3911 | 3908 | .dashboard-user-page .project-actions { margin-top: var(--gap-section); } | |
| 3912 | 3909 | } | |
| @@ -3974,7 +3971,7 @@ | |||
| 3974 | 3971 | ||
| 3975 | 3972 | .dashboard-item-page .section-header h2 { font-size: var(--text-subhead); } | |
| 3976 | 3973 | ||
| 3977 | - | @media (max-width: 768px) { | |
| 3974 | + | @media (max-width: 839px) { | |
| 3978 | 3975 | .dashboard-item-page .section-header { | |
| 3979 | 3976 | flex-direction: column; | |
| 3980 | 3977 | align-items: flex-start; | |
| @@ -6115,7 +6112,9 @@ | |||
| 6115 | 6112 | margin: var(--gap-page) 0 var(--gap-pane); | |
| 6116 | 6113 | padding: 0; | |
| 6117 | 6114 | display: grid; | |
| 6118 | - | grid-template-columns: repeat(3, 1fr); | |
| 6115 | + | /* A do-card stops being readable under about 200px, which is a fact about | |
| 6116 | + | the card. Three across is what that yields at full width. */ | |
| 6117 | + | grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| 6119 | 6118 | gap: var(--gap-section); | |
| 6120 | 6119 | width: 100%; | |
| 6121 | 6120 | } | |
| @@ -6165,12 +6164,6 @@ | |||
| 6165 | 6164 | border-bottom-color: currentColor; | |
| 6166 | 6165 | } | |
| 6167 | 6166 | ||
| 6168 | - | @media (max-width: 640px) { | |
| 6169 | - | .do-rail { | |
| 6170 | - | grid-template-columns: 1fr; | |
| 6171 | - | } | |
| 6172 | - | } | |
| 6173 | - | ||
| 6174 | 6167 | .do-card--wide { | |
| 6175 | 6168 | margin-top: var(--gap-page); | |
| 6176 | 6169 | width: 100%; | |
| @@ -6181,7 +6174,9 @@ | |||
| 6181 | 6174 | margin: var(--gap-section) 0 0; | |
| 6182 | 6175 | padding: 0; | |
| 6183 | 6176 | display: grid; | |
| 6184 | - | grid-template-columns: repeat(4, 1fr); | |
| 6177 | + | /* Title plus a short link list, so it holds up narrower than a do-card. | |
| 6178 | + | Four across at full width. */ | |
| 6179 | + | grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); | |
| 6185 | 6180 | gap: var(--gap-section); | |
| 6186 | 6181 | width: 100%; | |
| 6187 | 6182 | } | |
| @@ -6223,12 +6218,6 @@ | |||
| 6223 | 6218 | border-bottom-color: currentColor; | |
| 6224 | 6219 | } | |
| 6225 | 6220 | ||
| 6226 | - | @media (max-width: 640px) { | |
| 6227 | - | .contrast-rail { | |
| 6228 | - | grid-template-columns: 1fr; | |
| 6229 | - | } | |
| 6230 | - | } | |
| 6231 | - | ||
| 6232 | 6221 | .explore-links { | |
| 6233 | 6222 | display: flex; | |
| 6234 | 6223 | flex-wrap: wrap; | |
| @@ -7173,7 +7162,7 @@ | |||
| 7173 | 7162 | .site-footer-links a { margin: 0 var(--gap-section); color: inherit; text-decoration: none; } | |
| 7174 | 7163 | .site-footer-links a:hover { text-decoration: underline; } | |
| 7175 | 7164 | ||
| 7176 | - | @media (max-width: 768px) { | |
| 7165 | + | @media (max-width: 839px) { | |
| 7177 | 7166 | /* Git browser mobile */ | |
| 7178 | 7167 | .git-ref-bar { flex-wrap: wrap; gap: var(--gap-peer); } | |
| 7179 | 7168 | .git-repo-name { font-size: var(--text-subhead); } | |
| @@ -7306,7 +7295,7 @@ | |||
| 7306 | 7295 | } | |
| 7307 | 7296 | ||
| 7308 | 7297 | /* Doc pages, mobile */ | |
| 7309 | - | @media (max-width: 600px) { | |
| 7298 | + | @media (max-width: 599px) { | |
| 7310 | 7299 | .doc-title { font-size: var(--text-title); } | |
| 7311 | 7300 | .doc-body { font-size: var(--text-body); } | |
| 7312 | 7301 | .docs-index-title { font-size: var(--text-title); } | |
| @@ -7316,7 +7305,7 @@ | |||
| 7316 | 7305 | RESPONSIVE, 480px (phone) | |
| 7317 | 7306 | =========================================== */ | |
| 7318 | 7307 | ||
| 7319 | - | @media (max-width: 480px) { | |
| 7308 | + | @media (max-width: 599px) { | |
| 7320 | 7309 | .container { | |
| 7321 | 7310 | padding: var(--gap-section); | |
| 7322 | 7311 | } | |
| @@ -7584,7 +7573,7 @@ | |||
| 7584 | 7573 | margin-left: var(--gap-bound); | |
| 7585 | 7574 | } | |
| 7586 | 7575 | ||
| 7587 | - | @media (max-width: 900px) { | |
| 7576 | + | @media (max-width: 839px) { | |
| 7588 | 7577 | .discover-filter-toggle { display: inline-block; } | |
| 7589 | 7578 | .discover-layout { grid-template-columns: 1fr; } | |
| 7590 | 7579 | .discover-sidebar { display: none; } | |
| @@ -7600,7 +7589,7 @@ | |||
| 7600 | 7589 | .table-header.projects-header span:nth-child(3), .table-header.projects-header span:nth-child(4) { display: none; } | |
| 7601 | 7590 | } | |
| 7602 | 7591 | ||
| 7603 | - | @media (max-width: 480px) { | |
| 7592 | + | @media (max-width: 599px) { | |
| 7604 | 7593 | .table-header, .table-row { grid-template-columns: 1fr 60px; } | |
| 7605 | 7594 | .table-row-item { grid-template-columns: 1fr 30px; } | |
| 7606 | 7595 | .table-row-item .table-row-link { grid-template-columns: 1fr 60px; } | |
| @@ -11321,7 +11310,7 @@ | |||
| 11321 | 11310 | outline-offset: 2px; | |
| 11322 | 11311 | } | |
| 11323 | 11312 | ||
| 11324 | - | @media (max-width: 640px) { | |
| 11313 | + | @media (max-width: 599px) { | |
| 11325 | 11314 | .carousel-nav { width: 2rem; height: 2rem; font-size: var(--text-subhead); } | |
| 11326 | 11315 | } | |
| 11327 | 11316 | ||
| @@ -11333,7 +11322,9 @@ | |||
| 11333 | 11322 | .cp-editor-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--gap-section); flex-wrap: wrap; } | |
| 11334 | 11323 | .cp-editor-actions { display: flex; gap: var(--gap-section); } | |
| 11335 | 11324 | .cp-intro { color: var(--content-muted); margin: var(--gap-bound) 0 var(--gap-section); } | |
| 11336 | - | .cp-editor-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-section); align-items: start; } | |
| 11325 | + | /* Form beside preview. A code textarea below about 380px is not editable, so | |
| 11326 | + | that number is the pane's, not the viewport's, and the pair stacks itself. */ | |
| 11327 | + | .cp-editor-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); gap: var(--gap-section); align-items: start; } | |
| 11337 | 11328 | .cp-editor-form { display: flex; flex-direction: column; gap: var(--gap-peer); } | |
| 11338 | 11329 | .cp-code { width: 100%; min-height: 220px; font-family: var(--font-mono, ui-monospace, monospace); font-size: var(--text-note); line-height: 1.4; resize: vertical; } | |
| 11339 | 11330 | .cp-editor-buttons { display: flex; align-items: center; gap: var(--gap-section); margin-top: var(--gap-peer); } | |
| @@ -11352,8 +11343,6 @@ | |||
| 11352 | 11343 | .cp-status.cp-err { color: var(--warning); } | |
| 11353 | 11344 | .cp-reset { margin-top: var(--gap-pane); } | |
| 11354 | 11345 | .cp-locked-banner { margin: var(--gap-peer) 0 var(--gap-section); padding: var(--gap-section); border: 1px solid var(--warning); border-radius: var(--radius-control); background: color-mix(in oklch, var(--warning) 12%, var(--surface-page)); } | |
| 11355 | - | @media (max-width: 800px) { .cp-editor-grid { grid-template-columns: 1fr; } } | |
| 11356 | - | ||
| 11357 | 11346 | /* Layout-shift fix (audit Run 17 Frontend): reserve space for a cover image | |
| 11358 | 11347 | whose class didn't already set an aspect-ratio / fixed size. */ | |
| 11359 | 11348 | .proj-image-preview img { width: 120px; height: 120px; object-fit: cover; } | |
| @@ -11431,6 +11420,6 @@ | |||
| 11431 | 11420 | /* The narrow list layouts drop columns rather than wrap, and .row-info is the | |
| 11432 | 11421 | column that survives. Keeping the note there would crowd the title on a | |
| 11433 | 11422 | phone, where the tier heading above still carries the important half. */ | |
| 11434 | - | @media (max-width: 700px) { | |
| 11423 | + | @media (max-width: 599px) { | |
| 11435 | 11424 | .table-row .row-match-note { display: none; } | |
| 11436 | 11425 | } |
| @@ -212,7 +212,7 @@ | |||
| 212 | 212 | ||
| 213 | 213 | .pricing-cards { | |
| 214 | 214 | display: grid; | |
| 215 | - | grid-template-columns: repeat(3, 1fr); | |
| 215 | + | grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); | |
| 216 | 216 | gap: var(--gap-section); | |
| 217 | 217 | margin-bottom: var(--gap-pane); | |
| 218 | 218 | } | |
| @@ -225,7 +225,7 @@ | |||
| 225 | 225 | ||
| 226 | 226 | .content-choice-cards { | |
| 227 | 227 | display: grid; | |
| 228 | - | grid-template-columns: 1fr 1fr; | |
| 228 | + | grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); | |
| 229 | 229 | gap: var(--gap-section); | |
| 230 | 230 | margin-bottom: var(--gap-pane); | |
| 231 | 231 | } | |
| @@ -475,7 +475,7 @@ | |||
| 475 | 475 | ||
| 476 | 476 | /* Responsive */ | |
| 477 | 477 | ||
| 478 | - | @media (max-width: 768px) { | |
| 478 | + | @media (max-width: 839px) { | |
| 479 | 479 | .wizard-layout { | |
| 480 | 480 | flex-direction: column; | |
| 481 | 481 | } | |
| @@ -505,11 +505,6 @@ | |||
| 505 | 505 | white-space: nowrap; | |
| 506 | 506 | } | |
| 507 | 507 | ||
| 508 | - | .pricing-cards, | |
| 509 | - | .content-choice-cards { | |
| 510 | - | grid-template-columns: 1fr; | |
| 511 | - | } | |
| 512 | - | ||
| 513 | 508 | .type-grid { | |
| 514 | 509 | grid-template-columns: repeat(2, 1fr); | |
| 515 | 510 | } |
| @@ -1,4 +1,5 @@ | |||
| 1 | 1 | {% extends "base.html" %} | |
| 2 | + | {% import "_sheet.html" as sheet %} | |
| 2 | 3 | ||
| 3 | 4 | {% block title %}{{ item.title }} - Makenotwork{% endblock %} | |
| 4 | 5 | ||
| @@ -48,7 +49,7 @@ | |||
| 48 | 49 | } | |
| 49 | 50 | } | |
| 50 | 51 | </script> | |
| 51 | - | <link rel="stylesheet" href="/static/media-player.css"> | |
| 52 | + | {% call sheet::sheet("media-player.css") %}{% endcall %} | |
| 52 | 53 | {% endblock %} | |
| 53 | 54 | ||
| 54 | 55 | {% block content %} |
| @@ -1,11 +1,12 @@ | |||
| 1 | 1 | {% extends "base.html" %} | |
| 2 | + | {% import "_sheet.html" as sheet %} | |
| 2 | 3 | {% import "_island.html" as island %} | |
| 3 | 4 | ||
| 4 | 5 | {% block title %}{{ item.title }} - Library - Makenotwork{% endblock %} | |
| 5 | 6 | ||
| 6 | 7 | {% block head %} | |
| 7 | 8 | <meta name="robots" content="noindex"> | |
| 8 | - | <link rel="stylesheet" href="/static/media-player.css"> | |
| 9 | + | {% call sheet::sheet("media-player.css") %}{% endcall %} | |
| 9 | 10 | {% endblock %} | |
| 10 | 11 | ||
| 11 | 12 | {% block content %} |
| @@ -1,11 +1,12 @@ | |||
| 1 | 1 | {% extends "base.html" %} | |
| 2 | + | {% import "_sheet.html" as sheet %} | |
| 2 | 3 | {% import "_island.html" as island %} | |
| 3 | 4 | ||
| 4 | 5 | {% block title %}{{ item.title }} - Library - Makenotwork{% endblock %} | |
| 5 | 6 | ||
| 6 | 7 | {% block head %} | |
| 7 | 8 | <meta name="robots" content="noindex"> | |
| 8 | - | <link rel="stylesheet" href="/static/media-player.css"> | |
| 9 | + | {% call sheet::sheet("media-player.css") %}{% endcall %} | |
| 9 | 10 | {% endblock %} | |
| 10 | 11 | ||
| 11 | 12 | {% block content %} |
| @@ -1,4 +1,5 @@ | |||
| 1 | 1 | {% extends "base.html" %} | |
| 2 | + | {% import "_sheet.html" as sheet %} | |
| 2 | 3 | ||
| 3 | 4 | {% block title %}{{ item.title }} - Makenotwork{% endblock %} | |
| 4 | 5 | ||
| @@ -43,7 +44,7 @@ | |||
| 43 | 44 | }{% endif %} | |
| 44 | 45 | } | |
| 45 | 46 | </script> | |
| 46 | - | <link rel="stylesheet" href="/static/media-player.css"> | |
| 47 | + | {% call sheet::sheet("media-player.css") %}{% endcall %} | |
| 47 | 48 | {% endblock %} | |
| 48 | 49 | ||
| 49 | 50 | {% block content %} |
| @@ -1,10 +1,11 @@ | |||
| 1 | 1 | {% extends "base.html" %} | |
| 2 | + | {% import "_sheet.html" as sheet %} | |
| 2 | 3 | ||
| 3 | 4 | {% block title %}New Item - Makenotwork{% endblock %} | |
| 4 | 5 | {% block body_attrs %} class="padded-page"{% endblock %} | |
| 5 | 6 | ||
| 6 | 7 | {% block head %} | |
| 7 | - | <link rel="stylesheet" href="/static/wizard.css"> | |
| 8 | + | {% call sheet::sheet("wizard.css") %}{% endcall %} | |
| 8 | 9 | {% endblock %} | |
| 9 | 10 | ||
| 10 | 11 | {% block content %} |
| @@ -1,10 +1,11 @@ | |||
| 1 | 1 | {% extends "base.html" %} | |
| 2 | + | {% import "_sheet.html" as sheet %} | |
| 2 | 3 | ||
| 3 | 4 | {% block title %}Join - Makenotwork{% endblock %} | |
| 4 | 5 | {% block body_attrs %} class="padded-page"{% endblock %} | |
| 5 | 6 | ||
| 6 | 7 | {% block head %} | |
| 7 | - | <link rel="stylesheet" href="/static/wizard.css"> | |
| 8 | + | {% call sheet::sheet("wizard.css") %}{% endcall %} | |
| 8 | 9 | {% endblock %} | |
| 9 | 10 | ||
| 10 | 11 | {% block content %} |
| @@ -1,10 +1,11 @@ | |||
| 1 | 1 | {% extends "base.html" %} | |
| 2 | + | {% import "_sheet.html" as sheet %} | |
| 2 | 3 | ||
| 3 | 4 | {% block title %}New Project - Makenotwork{% endblock %} | |
| 4 | 5 | {% block body_attrs %} class="padded-page"{% endblock %} | |
| 5 | 6 | ||
| 6 | 7 | {% block head %} | |
| 7 | - | <link rel="stylesheet" href="/static/wizard.css"> | |
| 8 | + | {% call sheet::sheet("wizard.css") %}{% endcall %} | |
| 8 | 9 | {% endblock %} | |
| 9 | 10 | ||
| 10 | 11 | {% block content %} |