Skip to main content

max / goingson

Take the house font model, and declare Reglo as an override styles.css stated four faces of its own: a system sans stack, a system mono stack, Georgia, and a hand-written @font-face for Reglo. Three of those are now the house answer, generated into css/typography.css from makeover rather than restated here -- Quasi Mono and Quasi Body, cut by quasi-type from Atkinson Hyperlegible plus the house glyph set, and Reglo through the app-override layer, which is where a product names its brand face. Reglo's override carries weight 700. The @font-face it replaces had it, and a bold-only face declared without one reads as regular and gets a synthesised bold smeared on top. --font-body is gone: it was a second name for --font-sans and its three sites read that now. --font-serif stays stated, because the house model has two slots and a serif is not one of them, and --font-display falls back through it. --font-heading stays and is still an alias of sans -- it is not the brand slot here, unlike the MNW server's, which was renamed to --font-display in the same programme. One `font-family: monospace` was reaching past the token entirely.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-18 01:58 UTC
Signed with PGP, not checked
Commit: 63d08d57b517a1fdf39403d03bce5583b0b2ce2c
Parent: dad341e
7 files changed, +220 insertions, -56 deletions
M .gitignore +9
@@ -69,6 +69,15 @@
69 69 /src-tauri/frontend/css/geometry.css
70 70 /src-tauri/frontend/css/layout.css
71 71 /src-tauri/frontend/css/tables.css
72 + /src-tauri/frontend/css/typography.css
73 +
74 + # Cut by src-tauri/build.rs with quasi-type. Named file by file rather than as
75 + # a directory, unlike Balanced Breakfast's: Reglo lives here too and it is
76 + # upstream's face, committed rather than cut.
77 + /src-tauri/frontend/fonts/QuasiMono.woff2
78 + /src-tauri/frontend/fonts/QuasiBody.woff2
79 + /src-tauri/frontend/fonts/OFL-QuasiMono.txt
80 + /src-tauri/frontend/fonts/OFL-QuasiBody.txt
72 81
73 82 # Generated by src-tauri/build.rs from the column descriptions. The JSON is read
74 83 # off disk by the node tests, the JS by the running frontend; both are the same
M Cargo.lock +136 -6
@@ -127,6 +127,12 @@
127 127 "password-hash",
128 128 ]
129 129
130 + [[package]]
131 + name = "arrayvec"
132 + version = "0.7.8"
133 + source = "registry+https://github.com/rust-lang/crates.io-index"
134 + checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
135 +
130 136 [[package]]
131 137 name = "async-broadcast"
132 138 version = "0.7.2"
@@ -574,6 +580,20 @@
574 580 version = "1.25.2"
575 581 source = "registry+https://github.com/rust-lang/crates.io-index"
576 582 checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
583 + dependencies = [
584 + "bytemuck_derive",
585 + ]
586 +
587 + [[package]]
588 + name = "bytemuck_derive"
589 + version = "1.12.0"
590 + source = "registry+https://github.com/rust-lang/crates.io-index"
591 + checksum = "fc0e56a716f1e132ff6bf4bdac1c944a3fcdc1cae65f70a4a2a1ac3b401d2d1f"
592 + dependencies = [
593 + "proc-macro2",
594 + "quote",
595 + "syn 3.0.3",
596 + ]
577 597
578 598 [[package]]
579 599 name = "byteorder"
@@ -1746,6 +1766,7 @@
1746 1766 dependencies = [
1747 1767 "crc32fast",
1748 1768 "miniz_oxide",
1769 + "zlib-rs",
1749 1770 ]
1750 1771
1751 1772 [[package]]
@@ -1760,6 +1781,15 @@
1760 1781 source = "registry+https://github.com/rust-lang/crates.io-index"
1761 1782 checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
1762 1783
1784 + [[package]]
1785 + name = "font-types"
1786 + version = "0.12.3"
1787 + source = "registry+https://github.com/rust-lang/crates.io-index"
1788 + checksum = "75382bc7392ef10aad10935f92fc3db36d2d4dad0e5d96d8d65e04f89a07ec39"
1789 + dependencies = [
1790 + "bytemuck",
1791 + ]
1792 +
1763 1793 [[package]]
1764 1794 name = "foreign-types"
1765 1795 version = "0.5.0"
@@ -2245,6 +2275,7 @@
2245 2275 "quasi-http",
2246 2276 "quasi-router",
2247 2277 "quasi-tauri",
2278 + "quasi-type",
2248 2279 "quasi-webview",
2249 2280 "rand 0.10.2",
2250 2281 "reqwest",
@@ -3186,6 +3217,18 @@
3186 3217 "libc",
3187 3218 ]
3188 3219
3220 + [[package]]
3221 + name = "kurbo"
3222 + version = "0.13.1"
3223 + source = "registry+https://github.com/rust-lang/crates.io-index"
3224 + checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2"
3225 + dependencies = [
3226 + "arrayvec",
3227 + "euclid",
3228 + "polycool",
3229 + "smallvec",
3230 + ]
3231 +
3189 3232 [[package]]
3190 3233 name = "lab"
3191 3234 version = "0.11.0"
@@ -4510,6 +4553,15 @@
4510 4553 "universal-hash",
4511 4554 ]
4512 4555
4556 + [[package]]
4557 + name = "polycool"
4558 + version = "0.4.0"
4559 + source = "registry+https://github.com/rust-lang/crates.io-index"
4560 + checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6"
4561 + dependencies = [
4562 + "arrayvec",
4563 + ]
4564 +
4513 4565 [[package]]
4514 4566 name = "portable-atomic"
4515 4567 version = "1.15.0"
@@ -4677,6 +4729,22 @@
4677 4729 "tauri",
4678 4730 ]
4679 4731
4732 + [[package]]
4733 + name = "quasi-type"
4734 + version = "0.1.0"
4735 + dependencies = [
4736 + "brotli",
4737 + "font-types",
4738 + "kurbo",
4739 + "read-fonts",
4740 + "serde",
4741 + "sha2 0.10.9",
4742 + "skrifa",
4743 + "toml 1.1.4+spec-1.1.0",
4744 + "write-fonts",
4745 + "zip 6.0.0",
4746 + ]
4747 +
4680 4748 [[package]]
4681 4749 name = "quasi-webview"
4682 4750 version = "0.26.0"
@@ -4906,6 +4974,17 @@
4906 4974 source = "registry+https://github.com/rust-lang/crates.io-index"
4907 4975 checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
4908 4976
4977 + [[package]]
4978 + name = "read-fonts"
4979 + version = "0.43.0"
4980 + source = "registry+https://github.com/rust-lang/crates.io-index"
4981 + checksum = "a6b5cae85882cfb0167038e7726a426f47ebd808e67af78c2d6bcbb02acbf3ce"
4982 + dependencies = [
4983 + "bytemuck",
4984 + "font-types",
4985 + "once_cell",
4986 + ]
4987 +
4909 4988 [[package]]
4910 4989 name = "redox_syscall"
4911 4990 version = "0.5.18"
@@ -5675,6 +5754,16 @@
5675 5754 source = "registry+https://github.com/rust-lang/crates.io-index"
5676 5755 checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
5677 5756
5757 + [[package]]
5758 + name = "skrifa"
5759 + version = "0.46.0"
5760 + source = "registry+https://github.com/rust-lang/crates.io-index"
5761 + checksum = "de0bbcc507e438bfe765692ae5228059959781db7430fe36e1cfd569e7c88c89"
5762 + dependencies = [
5763 + "bytemuck",
5764 + "read-fonts",
5765 + ]
5766 +
5678 5767 [[package]]
5679 5768 name = "slab"
5680 5769 version = "0.4.12"
@@ -6330,7 +6419,7 @@
6330 6419 "tokio",
6331 6420 "url",
6332 6421 "windows-sys 0.60.2",
6333 - "zip",
6422 + "zip 4.6.1",
6334 6423 ]
6335 6424
6336 6425 [[package]]
@@ -8014,6 +8103,19 @@
8014 8103 source = "registry+https://github.com/rust-lang/crates.io-index"
8015 8104 checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
8016 8105
8106 + [[package]]
8107 + name = "write-fonts"
8108 + version = "0.52.0"
8109 + source = "registry+https://github.com/rust-lang/crates.io-index"
8110 + checksum = "843cebb7bd36359861dbce43d54ac8b33dfdf7b80a95913adc1ef7c7bb881e62"
8111 + dependencies = [
8112 + "font-types",
8113 + "indexmap 2.14.0",
8114 + "kurbo",
8115 + "log",
8116 + "read-fonts",
8117 + ]
8118 +
8017 8119 [[package]]
8018 8120 name = "writeable"
8019 8121 version = "0.6.3"
@@ -8316,12 +8418,44 @@
8316 8418 "memchr",
8317 8419 ]
8318 8420
8421 + [[package]]
8422 + name = "zip"
8423 + version = "6.0.0"
8424 + source = "registry+https://github.com/rust-lang/crates.io-index"
8425 + checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b"
8426 + dependencies = [
8427 + "arbitrary",
8428 + "crc32fast",
8429 + "flate2",
8430 + "indexmap 2.14.0",
8431 + "memchr",
8432 + "zopfli",
8433 + ]
8434 +
8435 + [[package]]
8436 + name = "zlib-rs"
8437 + version = "0.6.7"
8438 + source = "registry+https://github.com/rust-lang/crates.io-index"
8439 + checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12"
8440 +
8319 8441 [[package]]
8320 8442 name = "zmij"
8321 8443 version = "1.0.23"
8322 8444 source = "registry+https://github.com/rust-lang/crates.io-index"
8323 8445 checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
8324 8446
8447 + [[package]]
8448 + name = "zopfli"
8449 + version = "0.8.3"
8450 + source = "registry+https://github.com/rust-lang/crates.io-index"
8451 + checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249"
8452 + dependencies = [
8453 + "bumpalo",
8454 + "crc32fast",
8455 + "log",
8456 + "simd-adler32",
8457 + ]
8458 +
8325 8459 [[package]]
8326 8460 name = "zvariant"
8327 8461 version = "5.14.0"
@@ -8363,10 +8497,6 @@
8363 8497 "winnow 1.0.4",
8364 8498 ]
8365 8499
8366 - [[patch.unused]]
8367 - name = "ops-status"
8368 - version = "0.1.0"
8369 -
8370 8500 [[patch.unused]]
8371 8501 name = "quasi-axum"
8372 8502 version = "0.26.0"
@@ -8384,5 +8514,5 @@
8384 8514 version = "0.1.0"
8385 8515
8386 8516 [[patch.unused]]
8387 - name = "quasi-type"
8517 + name = "ops-status"
8388 8518 version = "0.1.0"
@@ -19,6 +19,12 @@
19 19 # and holds both drift checks this build.rs used to carry itself: touch density
20 20 # as of 0.17, breakpoints as of 0.18.
21 21 makeover-build = "0.42.0"
22 + # Cuts the two house faces into frontend/fonts/. A git dependency because
23 + # quasi-type is `publish = false`, which is also why makeover-build cannot do
24 + # this and only emits the CSS that fetches the result. The rev is the one
25 + # shop's `shop-font`, Balanced Breakfast and Alloy's `QUASI_TYPE_REV` name: the
26 + # house face is one face, so they move together or a user sees two Quasi Monos.
27 + quasi-type = { git = "https://makenot.work/git/max/quasi-type.git", version = "0.1", rev = "e40330602e68fbdd2a9d2917bdec33a7ce573a1f" }
22 28 # The table CSS is generated here too: the columns are this app's, so the
23 29 # shared helper cannot know them, but the tracks and the narrowing rules come
24 30 # from the description rather than from hand-written nth-child cuts.
@@ -612,16 +612,61 @@
612 612 const TUNING_WIDTHS: &[u16] = &[1024, 1400];
613 613
614 614 fn main() {
615 - // All three generated files: themes/, geometry.css, layout.css. The
616 - // geometry emitter moved out too once density selection was settled:
617 - // touch is a capability, so it hangs off (hover: none), (pointer: coarse)
618 - // rather than a user-agent string or a breakpoint.
619 - makeover_build::tauri_frontend(
615 + // All four generated files: themes/, geometry.css, layout.css,
616 + // typography.css. The geometry emitter moved out once density selection
617 + // was settled -- touch is a capability, so it hangs off (hover: none),
618 + // (pointer: coarse) rather than a user-agent string or a breakpoint -- and
619 + // typography followed it for the same reason, once there was a house
620 + // answer to state.
621 + //
622 + // Reglo is the third token and it is here rather than in styles.css
623 + // because that is what layer 0 is for. It used to be a hand-written
624 + // `@font-face` plus a `--font-display` this repository defined for itself;
625 + // declared as an override it is the same shape as the two house slots. The
626 + // face is committed rather than cut: it is upstream's, unmodified, and
627 + // quasi-type has no part in it.
628 + //
629 + // Note this app's `--font-heading` is an alias of sans and is NOT the
630 + // brand slot, unlike the MNW server's, which was renamed to
631 + // `--font-display` in the same programme so one name means one thing
632 + // tree-wide.
633 + makeover_build::tauri_frontend_with(
620 634 env!("CARGO_MANIFEST_DIR"),
621 635 &makeover_build::Emit::default(),
622 636 Some(".ui-mode-mobile"),
637 + &makeover_build::Typography::house("../fonts").with_override(
638 + makeover_build::FontOverride::new(
639 + makeover_build::FontSlot::Display,
640 + "'Reglo', var(--font-serif)",
641 + )
642 + // 700, or the browser reads a bold-only face as regular and
643 + // synthesises a second bold on top of it. The hand-written
644 + // `@font-face` this replaces carried the weight and dropping it
645 + // would be a silent smear on every heading.
646 + .with_face(makeover_build::FontFace::new("Reglo", ["Reglo-Bold.woff2"]).weight("700")),
647 + ),
623 648 );
624 649
650 + // The faces typography.css fetches. Cut rather than committed, the rule
651 + // shop and the Alloy image already follow: a face in the repository is a
652 + // second source of truth that nothing rebuilds. The base is downloaded
653 + // into OUT_DIR once and checksummed against quasi-type's pins, so a warm
654 + // target directory needs no network. Reglo sits in the same directory and
655 + // is not cut, which is why .gitignore names the two Quasi files rather
656 + // than the directory.
657 + quasi_type::cut_web(
658 + &Path::new(env!("CARGO_MANIFEST_DIR"))
659 + .join("frontend")
660 + .join("fonts"),
661 + &Path::new(&std::env::var("OUT_DIR").expect("cargo sets OUT_DIR")).join("bases"),
662 + false,
663 + &[
664 + ("quasi-mono", makeover_build::WEBFONT_MONO_FILE),
665 + ("quasi-body", makeover_build::WEBFONT_SANS_FILE),
666 + ],
667 + )
668 + .expect("cut the house faces");
669 +
625 670 // The columns are this app's, so the shared helper cannot know them, but
626 671 // what is done with them comes from the description all the same.
627 672 let frontend = Path::new(env!("CARGO_MANIFEST_DIR")).join("frontend");
@@ -51,6 +51,7 @@
51 51 descriptions in src-tauri/build.rs. All three emit into `@layer
52 52 makeover`. Geometry first, so the stylesheet can read --gap-* and
53 53 --step-* off :root. -->
54 + <link rel="stylesheet" href="css/typography.css">
54 55 <link rel="stylesheet" href="css/geometry.css">
55 56 <link rel="stylesheet" href="css/layout.css">
56 57 <link rel="stylesheet" href="css/tables.css">
@@ -284,14 +284,9 @@
284 284 @layer base, components, responsive;
285 285
286 286 @layer base {
287 - /* 1. Font Face */
288 - @font-face {
289 - font-family: 'Reglo';
290 - src: url('../fonts/Reglo-Bold.woff2') format('woff2');
291 - font-weight: 700;
292 - font-style: normal;
293 - font-display: swap;
294 - }
287 + /* 1. Font Face: none here. The two house faces and this app's Reglo are
288 + declared in css/typography.css, generated from makeover -- Reglo through
289 + the app-override layer, which is where a product names its brand face. */
295 290
296 291 /* 2. CSS Reset & Base */
297 292 *, *::before, *::after {
@@ -406,14 +401,20 @@
406 401 /* Spacing: see css/geometry.css. --gap-bound, --gap-peer, --gap-group,
407 402 --gap-section, --gap-pane, --gap-page, over a --step-* scale. */
408 403
409 - --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
404 + /* Faces: see css/typography.css. --font-mono is Quasi Mono and
405 + --font-sans is Quasi Body, both cut by quasi-type from Atkinson
406 + Hyperlegible plus the house glyph set; --font-display is Reglo,
407 + declared as this app's override. None of the three is defined here,
408 + and defining one would shadow the house answer for this app alone.
409 + --font-serif is the one token still stated below: the house model has
410 + two slots and a serif is not one of them, and --font-display falls
411 + back through it. */
410 412 --font-serif: Georgia, 'Times New Roman', serif;
411 - --font-mono: 'SF Mono', 'Consolas', 'Liberation Mono', monospace;
412 - --font-display: 'Reglo', var(--font-serif);
413 413
414 - /* Semantic font aliases */
414 + /* Semantic font alias. NOT the brand slot -- that is --font-display.
415 + --font-body went with the stated faces: it was a second name for
416 + --font-sans and every site reading it now reads that. */
415 417 --font-heading: var(--font-sans);
416 - --font-body: var(--font-sans);
417 418
418 419 /* Typography scale */
419 420 --font-size-xxs: 0.65rem; /* Tiny badges, indicators */
@@ -4275,7 +4276,7 @@
4275 4276 border: var(--border-width) solid var(--border);
4276 4277 border-radius: var(--radius-sm);
4277 4278 color: var(--content);
4278 - font-family: var(--font-body);
4279 + font-family: var(--font-sans);
4279 4280 }
4280 4281
4281 4282 .day-plan-date-display {
@@ -6707,7 +6708,7 @@
6707 6708
6708 6709 .selected-file-name {
6709 6710 color: var(--content-secondary);
6710 - font-family: monospace;
6711 + font-family: var(--font-mono);
6711 6712 font-size: var(--font-size-sm);
6712 6713 }
6713 6714
@@ -8068,7 +8069,7 @@
8068 8069 padding: var(--gap-bound) var(--gap-group);
8069 8070 border: var(--border-width-sm) solid var(--border);
8070 8071 background: var(--surface-overlay);
8071 - font-family: var(--font-body);
8072 + font-family: var(--font-sans);
8072 8073 font-size: var(--font-size-md);
8073 8074 cursor: pointer;
8074 8075 }
@@ -8110,7 +8111,7 @@
8110 8111 }
8111 8112
8112 8113 .kanban-column-count {
8113 - font-family: var(--font-body);
8114 + font-family: var(--font-sans);
8114 8115 font-size: var(--font-size-sm);
8115 8116 color: var(--content-secondary);
8116 8117 }
@@ -1,28 +1,0 @@
1 - /* Generated by makeover-build from makeover. Do not edit.
2 - Two needs, two names, then a system generic. The faces are cut by
3 - quasi-type from Atkinson Hyperlegible plus the house glyph set, and
4 - both are variable over wght 200-800 in one file, which is why the
5 - @font-face rules name the range. The mono face opens at ExtraLight.
6 - A third token here is this product's own brand face, declared as an
7 - override in its build script. */
8 -
9 - @font-face {
10 - font-family: "Quasi Mono";
11 - src: url("../fonts/QuasiMono.woff2") format("woff2");
12 - font-weight: 200 800;
13 - font-style: normal;
14 - font-display: swap;
15 - }
16 -
17 - @font-face {
18 - font-family: "Quasi Body";
19 - src: url("../fonts/QuasiBody.woff2") format("woff2");
20 - font-weight: 200 800;
21 - font-style: normal;
22 - font-display: swap;
23 - }
24 -
25 - :root {
26 - --font-mono: "Quasi Mono", monospace;
27 - --font-sans: "Quasi Body", sans-serif;
28 - }