diff --git a/.mise.toml b/.mise.toml
index 30f67a4..8fff695 100644
--- a/.mise.toml
+++ b/.mise.toml
@@ -31,11 +31,6 @@ description = "Regenerate docs/src/data/repos.json from the Lab271 GitHub org"
dir = "docs"
run = "node scripts/refresh-repos.mjs"
-[tasks.docs-marks]
-description = "Regenerate src/assets/logo.svg and badge.svg (Inter outlined to paths)"
-dir = "docs"
-run = "uv run scripts/refresh-marks.py"
-
[tasks.docs-icons]
description = "Re-export the favicon/apple-touch-icon PNGs from src/assets/badge.svg"
dir = "docs"
diff --git a/AGENTS.md b/AGENTS.md
index 4dc7161..eef9649 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -23,7 +23,6 @@ mise run docs-dev # dev server at http://localhost:4321/
mise run docs-check # astro check (type/content check)
mise run docs-build # static build into docs/dist
mise run docs-repos # regenerate docs/src/data/repos.json from the Lab271 org (needs `gh` auth)
-mise run docs-marks # regenerate the logo/badge SVGs (needs uv)
mise run docs-icons # re-export the favicon PNGs from src/assets/badge.svg (needs librsvg)
```
@@ -38,11 +37,12 @@ When starting the dev server directly (not via mise), use background mode:
- `src/intro.md`: the intro paragraphs, imported into the landing page.
- `src/styles/custom.css`: Lab271 brand theme (colors, fonts) mapped onto
Starlight's CSS custom properties.
- - `src/assets/logo.svg`: the horizontal wordmark used in the nav bar.
+ - `src/assets/logo.svg`: the horizontal wordmark used in the nav bar. Vendored
+ from the design team's final artwork (the Lab271 design refresh) rather than
+ generated - see Branding below.
- `src/assets/badge.svg`: the badge mark, and the master for the favicon PNGs
- in `public/`. Both SVGs are generated by `scripts/refresh-marks.py`
- (`mise run docs-marks`); the PNGs by `scripts/refresh-icons.sh`
- (`mise run docs-icons`).
+ in `public/`. Also vendored artwork. The PNGs are re-exported from it with
+ `scripts/refresh-icons.sh` (`mise run docs-icons`).
- `src/assets/hero.jpg`: the hero photo.
- `src/data/repos.json`: committed, auto-generated list of public `Lab271`
repos that carry an open source license. Regenerate with `mise run
@@ -63,23 +63,33 @@ When starting the dev server directly (not via mise), use background mode:
## Branding
-The theme implements the Lab271 brand kit (`labs-branding`, in particular
-`brand/visual-identity.md` and `brand/tokens/lab271.tokens.json`). When touching
-colors, type or the marks, read those first. The rules that shaped what is here:
+The theme implements the Lab271 design refresh (see ADR-0005 in
+`Lab271/www.lab271.io`), which supersedes the `labs-branding`
+(`brand/visual-identity.md`, `brand/tokens/lab271.tokens.json`) Navy/Primary
+Blue/Teal system this site carried before. `labs-branding` has not been
+re-derived from the refresh yet, so it is temporarily stale - treat this
+repo's `custom.css` and its `www.lab271.io` sibling as authoritative in the
+meantime. The rules that shaped what is here:
-- **Palette.** Navy `#1A1F36` anchors dark surfaces, including the nav bar in
- both color modes. Primary Blue `#6C8EEF` is the signature, Blue Light
- `#A8C0FF` its gradient partner. Teal `#36C5B0` is a spark: at most one per
- composition, which here is the rule in the badge. Never pure black.
+- **Palette.** Near-black `#020C17` anchors dark surfaces, including the nav
+ bar in both color modes (never pure black). Cyan `#1EE8ED` (dark mode) /
+ `#18B9BD` (light mode, darkened for contrast) is the signature accent.
+ Orange `#FF7000`/`#FF8D33` is a spark: at most one per composition, which
+ here is the rule in the badge. Light mode's canvas is a warm paper off-white
+ (`#FAF9F5`), not a cool gray.
- **Type.** Inter and JetBrains Mono are the open stand-ins for TT Interphases
and TT Interphases Mono, the licensed SBP faces that cannot ship on a public
- build. Sentence case headings with tight tracking. Mono is "a pinch of tech",
- so it is limited to the `e = 2.71828` motif and the language labels.
-- **Marks.** `logo.svg` and `badge.svg` set Inter outlined to paths, so they
- render without the font installed. The badge follows the brand kit's concept A,
- "the door plate". Change them by editing `scripts/refresh-marks.py` and
- re-running it, not by editing the path data.
-- **Written "Lab271"**, sentence case, no space. Never "LAB271".
+ build - unchanged by the refresh. Sentence case headings with tight
+ tracking. Mono is "a pinch of tech", so it is limited to the `e = 2.71828`
+ motif and the language labels.
+- **Marks.** `logo.svg` and `badge.svg` are vendored directly from the design
+ team's final artwork for the refresh, not generated - the previous
+ Inter-outlined-to-paths approach (`scripts/refresh-marks.py`) is retired.
+ Update them by replacing the SVG file with a new export from the design
+ source, not by hand-editing the path data.
+- **Written "Lab271"**, sentence case, no space, in all prose and copy. Never
+ "LAB271" in running text - the all-caps treatment is reserved for the
+ wordmark graphic itself (`logo.svg`).
- US English throughout.
- No em dashes in the copy. `docs/scripts/refresh-repos.mjs` normalizes them out
of upstream GitHub descriptions too.
diff --git a/docs/public/apple-touch-icon.png b/docs/public/apple-touch-icon.png
index 17006ee..042d963 100644
Binary files a/docs/public/apple-touch-icon.png and b/docs/public/apple-touch-icon.png differ
diff --git a/docs/public/favicon-32x32.png b/docs/public/favicon-32x32.png
index c5c2aa7..d09d114 100644
Binary files a/docs/public/favicon-32x32.png and b/docs/public/favicon-32x32.png differ
diff --git a/docs/public/favicon.png b/docs/public/favicon.png
index a14ea23..5c375c8 100644
Binary files a/docs/public/favicon.png and b/docs/public/favicon.png differ
diff --git a/docs/scripts/refresh-marks.py b/docs/scripts/refresh-marks.py
deleted file mode 100755
index 5be3c51..0000000
--- a/docs/scripts/refresh-marks.py
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/env -S uv run --script
-# /// script
-# requires-python = ">=3.12"
-# dependencies = ["fonttools>=4.60", "brotli>=1.1"]
-# ///
-"""Generate the Lab271 wordmark and badge SVGs.
-
-Both marks set text in Inter, the brand kit's open stand-in for TT Interphases.
-Rather than relying on Inter being installed wherever the SVG is rendered, this
-outlines the glyphs to paths, which is what labs-branding's logo/README.md asks
-for before an SVG ships.
-
-Run via `mise run docs-marks`, then `mise run docs-icons` to re-export the
-favicon PNGs from the new badge.
-
-Palette and lockup rules: labs-branding, brand/visual-identity.md sections 1-3.
-"""
-
-from __future__ import annotations
-
-import urllib.request
-from pathlib import Path
-
-from fontTools.misc.transform import Transform
-from fontTools.pens.boundsPen import BoundsPen
-from fontTools.pens.svgPathPen import SVGPathPen
-from fontTools.pens.transformPen import TransformPen
-from fontTools.ttLib import TTFont
-
-# Inter, latin subset, one file per weight. Pinned to a major version so the
-# outlines don't shift under us without a deliberate bump.
-FONT_URLS = {
- 600: "https://cdn.jsdelivr.net/npm/@fontsource/inter@5/files/inter-latin-600-normal.woff2",
- 700: "https://cdn.jsdelivr.net/npm/@fontsource/inter@5/files/inter-latin-700-normal.woff2",
-}
-
-NAVY = "#1A1F36"
-BLUE = "#6C8EEF"
-BLUE_LIGHT = "#A8C0FF"
-TEAL = "#36C5B0"
-WHITE = "#FFFFFF"
-
-HERE = Path(__file__).resolve().parent
-ASSETS = HERE.parent / "src" / "assets"
-CACHE = HERE / ".font-cache"
-
-
-def font(weight: int) -> TTFont:
- CACHE.mkdir(exist_ok=True)
- path = CACHE / f"inter-{weight}.woff2"
- if not path.exists():
- print(f"downloading {FONT_URLS[weight]}")
- with urllib.request.urlopen(FONT_URLS[weight]) as response:
- path.write_bytes(response.read())
- return TTFont(path)
-
-
-def run(weight: int, text: str, size: float, tracking: float = 0.0, x: float = 0.0, y: float = 0.0):
- """Outline `text` at `size`, returning (path data, advance width, ink bounds).
-
- `y` is the baseline; `tracking` is extra space per glyph, in the same units
- as `size`. No shaping or kerning: the marks are short and set with explicit
- tracking anyway.
- """
- face = font(weight)
- scale = size / face["head"].unitsPerEm
- cmap = face.getBestCmap()
- glyphs = face.getGlyphSet()
- widths = face["hmtx"]
-
- pen_x = x
- paths = []
- bounds = BoundsPen(glyphs)
- for char in text:
- name = cmap[ord(char)]
- placement = Transform(scale, 0, 0, -scale, pen_x, y)
- svg = SVGPathPen(glyphs, ntos=lambda value: f"{value:.2f}")
- glyphs[name].draw(TransformPen(svg, placement))
- if svg.getCommands():
- paths.append(svg.getCommands())
- glyphs[name].draw(TransformPen(bounds, placement))
- pen_x += widths[name][0] * scale + tracking
- # the trailing tracking is space after the last glyph, not part of the run
- return " ".join(paths), pen_x - x - tracking, bounds.bounds
-
-
-def wordmark() -> str:
- """Horizontal lockup: white "Lab", blue-light "271", tight tracking."""
- size, tracking, baseline = 56, -1.1, 100.0
- lab, lab_width, lab_bounds = run(700, "Lab", size, tracking, 0, baseline)
- num, _, num_bounds = run(700, "271", size, tracking, lab_width + tracking, baseline)
-
- x0 = min(lab_bounds[0], num_bounds[0])
- y0 = min(lab_bounds[1], num_bounds[1])
- x1 = max(lab_bounds[2], num_bounds[2])
- y1 = max(lab_bounds[3], num_bounds[3])
-
- return f"""
-"""
-
-
-def badge() -> str:
- """Concept A, "the door plate": tracked "Lab" over a large "271", teal rule."""
- side, radius = 512, 117 # radius keeps concept A's 32-at-140px proportion
- _, lab_width, _ = run(600, "Lab", 80, 14.6)
- _, num_width, _ = run(700, "271", 212, -4)
- # centre both lines, ignoring the trailing tracking on "Lab"
- lab, _, _ = run(600, "Lab", 80, 14.6, (side - lab_width) / 2, 168)
- num, _, _ = run(700, "271", 212, -4, (side - num_width) / 2, 372)
-
- rule_width, rule_height = 190, 22
- return f"""
-"""
-
-
-for name, svg in (("logo.svg", wordmark()), ("badge.svg", badge())):
- (ASSETS / name).write_text(svg)
- print(f"wrote {ASSETS / name}")
diff --git a/docs/src/assets/badge.svg b/docs/src/assets/badge.svg
index 3530118..c4aaa18 100644
--- a/docs/src/assets/badge.svg
+++ b/docs/src/assets/badge.svg
@@ -1,11 +1,12 @@
-