diff --git a/nextjs-app/app/opengraph-image.tsx b/nextjs-app/app/opengraph-image.tsx
index e3af9a6..a62de42 100644
--- a/nextjs-app/app/opengraph-image.tsx
+++ b/nextjs-app/app/opengraph-image.tsx
@@ -31,6 +31,8 @@ async function font(file: string) {
* The mark, as a data URI. Satori has no access to the public/ URL space, so
* the artwork is read off disk and inlined. This is the same file the header
* serves — public/brand/mark.png — so the card can never drift from the site.
+ * The 47×56 box below is that file's 176:208 ratio; re-crop the artwork and
+ * this has to move with it, or Satori will stretch it.
*/
async function markDataUri() {
const png = await readFile(join(process.cwd(), 'public', 'brand', 'mark.png'));
@@ -72,7 +74,7 @@ export default async function OpengraphImage() {
{/* Lockup */}
{/* eslint-disable-next-line @next/next/no-img-element */}
-

+
school
compare
diff --git a/nextjs-app/components/Logo.tsx b/nextjs-app/components/Logo.tsx
index 3301f13..d6e8114 100644
--- a/nextjs-app/components/Logo.tsx
+++ b/nextjs-app/components/Logo.tsx
@@ -12,6 +12,10 @@
* ground is teal, because there the teal pin's silhouette
* disappears and only the white window survives.
*
+ * Both are written onto one 176×208 canvas with the artwork at the same
+ * height, so they are drop-in swappable — see ASPECT below for why that
+ * matters rather than merely being neat.
+ *
* `variant="auto"` serves the on-dark artwork to dark-theme viewers via a
*
source, so this needs no JavaScript and no client boundary.
*
@@ -29,8 +33,22 @@
const MARK_LIGHT = '/brand/mark.png';
const MARK_ON_DARK = '/brand/mark-on-dark.png';
-/** Intrinsic aspect of the artwork, used to derive width from height. */
-const ASPECT = 153 / 189;
+/**
+ * Intrinsic size of the artwork files, used to derive width from height.
+ *
+ * Both colourways are deliberately written onto the SAME canvas at the same
+ * artwork height, so this one ratio is correct for either of them. That is not
+ * tidiness — it is required. `variant="auto"` renders a single
whose
+ * srcset swaps the file underneath it, so the width/height attributes are
+ * shared by both colourways and cannot be varied per file. When the two were
+ * tightly cropped they had different ratios (0.810 and 0.875) and different
+ * padding, which meant a wrong aspect hint before load — a reflow on load
+ * under `width: auto` — and a visible jump in logo size whenever the OS theme
+ * flipped. Re-crop or replace one file and you must re-normalise both.
+ */
+const ART_WIDTH = 176;
+const ART_HEIGHT = 208;
+const ASPECT = ART_WIDTH / ART_HEIGHT;
interface LogoMarkProps {
className?: string;
diff --git a/nextjs-app/public/brand/mark-on-dark.png b/nextjs-app/public/brand/mark-on-dark.png
index d76e82b..d9d94c0 100644
Binary files a/nextjs-app/public/brand/mark-on-dark.png and b/nextjs-app/public/brand/mark-on-dark.png differ
diff --git a/nextjs-app/public/brand/mark.png b/nextjs-app/public/brand/mark.png
index e02914f..ca8ecb6 100644
Binary files a/nextjs-app/public/brand/mark.png and b/nextjs-app/public/brand/mark.png differ