From 9668cc256b0eb63ae3cde17f7d697b3a2f2a6997 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Aug 2026 21:21:45 +0000 Subject: [PATCH] Ge ALVA-ytan sin egen typografi enligt ALVA-SPEC-001 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ALVA satte inget eget snitt och ärvde därför värdapplikationens `Crimson Text` — en antikva. Specens paragraf 6 föreskriver DIN 2014, med FF DIN och IBM Plex Sans som tillåtna alternativ. Skillnaden är inte kosmetisk. Bokstavsformen är det första som säger vilken tradition ett verktyg tillhör, och dokumentet beskrev ett tyskt industrisystem medan skärmen visade en bokstavsform ur en helt annan. På en telefon, där ingenting annat konkurrerar om intrycket, var det i praktiken allt man såg. Fallkedjan är därför inte godtycklig: en organisation som licensierat DIN får DIN, övriga faller ned genom grotesker som delar dess karaktär, och aldrig till en antikva. Beteckningar och mätvärden sätts med fast teckenbredd och tabellsiffror — en beteckning jämförs oftare än den läses. Reglerna gäller bara ALVA-ytan; butiken lämnas som den är. Fyra tester låser snittet, kaskaden och siffrorna, inklusive att fallkedjan aldrig slutar i en antikva. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt --- felsokning/app/src/alva/system.ts | 21 ++++++++ .../src/felsokning/__tests__/alva-yta.test.ts | 38 ++++++++++++++ felsokning/app/src/index.css | 51 +++++++++++++++++++ felsokning/app/src/pages/alva/Ram.tsx | 4 +- 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/felsokning/app/src/alva/system.ts b/felsokning/app/src/alva/system.ts index 2b3f76d..1f960c5 100644 --- a/felsokning/app/src/alva/system.ts +++ b/felsokning/app/src/alva/system.ts @@ -168,3 +168,24 @@ export const PLATTFORMSVERSION = "ALVA 1.0"; export const RUTNÄT = 8; export const steg = (antal: number) => `${antal * RUTNÄT}px`; + +// ---- Typografi (ALVA-SPEC-001 · paragraf 6) --------------------------- +// +// En familj genomgående, åtskild med vikt, storlek, spärrning och +// versalisering. Produktionssnittet är DIN 2014; tillåtna alternativ är +// FF DIN och IBM Plex Sans. Ordningen nedan är därför inte godtycklig: +// en organisation som licensierat DIN får DIN, övriga faller ned genom +// grotesker som delar dess karaktär — aldrig till en antikva. +// +// Detta var länge ett avsteg i praktiken. ALVA-ytan satte inget eget +// snitt och ärvde därför värdapplikationens `Crimson Text` — en antikva. +// Specen beskrev ett tyskt industrisystem medan skärmen visade en +// bokstavsform från en helt annan tradition, och det syntes direkt på en +// telefon där ingenting annat konkurrerade om intrycket. +export const TYPSNITT = + '"DIN 2014", "FF DIN", "IBM Plex Sans", "Inter", "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif'; + +// Identifierare och mätvärden sätts med fast teckenbredd så att siffror +// står i kolumn — beteckningar jämförs oftare än de läses. +export const TYPSNITT_MONO = + 'ui-monospace, "IBM Plex Mono", "SF Mono", "Cascadia Mono", Menlo, Consolas, "Liberation Mono", monospace'; diff --git a/felsokning/app/src/felsokning/__tests__/alva-yta.test.ts b/felsokning/app/src/felsokning/__tests__/alva-yta.test.ts index b75d957..fb0542f 100644 --- a/felsokning/app/src/felsokning/__tests__/alva-yta.test.ts +++ b/felsokning/app/src/felsokning/__tests__/alva-yta.test.ts @@ -156,3 +156,41 @@ describe("ALVA-ytan håller sig inom skärmbredden", () => { expect(komponenter).toContain("min-w-0 flex-1"); }); }); + +// ---- Typografin är specens, inte värdapplikationens -------------------- +// +// ALVA-ytan satte länge inget eget snitt och ärvde därför butikens +// `Crimson Text` — en antikva. Specen (ALVA-SPEC-001, paragraf 6) +// föreskriver DIN 2014 med FF DIN och IBM Plex Sans som tillåtna +// alternativ. Skillnaden är inte kosmetisk: bokstavsformen är det första +// som säger vilken tradition ett verktyg tillhör, och på en telefon där +// ingenting annat konkurrerar om intrycket var det allt man såg. +describe("ALVA-ytan bär sin egen typografi", () => { + const css = readFileSync("src/index.css", "utf8"); + const ram = filer.find(([n]) => n.endsWith("pages/alva/Ram.tsx"))![1]; + const system = filer.find(([n]) => n.endsWith("alva/system.ts"))![1]; + + it("ramen märker ytan så att kaskaden når den", () => { + expect(ram).toContain("alva-yta"); + }); + + it("snittet är deklarerat i systemfilen med specens ordning", () => { + const stack = system.match(/export const TYPSNITT =[\s\S]*?;/)?.[0] ?? ""; + expect(stack).toContain("DIN 2014"); + expect(stack).toContain("FF DIN"); + expect(stack).toContain("IBM Plex Sans"); + // Fallkedjan får aldrig sluta i en antikva. `sans-serif` är den + // generiska groteskfamiljen och alltså inte det som avses. + expect(stack).not.toMatch(/(? { + const regel = css.match(/\.alva-yta[\s\S]*?\{[\s\S]*?\}/)?.[0] ?? ""; + expect(regel).toContain("DIN 2014"); + expect(css).toContain(".alva-yta h1"); + }); + + it("siffror sätts med fast bredd så beteckningar går att jämföra", () => { + expect(css).toContain("tabular-nums"); + }); +}); diff --git a/felsokning/app/src/index.css b/felsokning/app/src/index.css index febb375..39e7691 100644 --- a/felsokning/app/src/index.css +++ b/felsokning/app/src/index.css @@ -156,6 +156,57 @@ } } +/* ---- ALVA-ytan (ALVA-SPEC-001 · paragraf 6) -------------------------- + * + * Värdapplikationen sätter en antikva på body. ALVA ärvde den, vilket är + * fel tradition för ett system som beskriver sig som ett tyskt + * industriverktyg. Reglerna nedan gäller bara ALVA-ytan; butiken lämnas + * som den är. + * + * Snittet deklareras i src/alva/system.ts och speglas här därför att + * kaskaden måste nå även de element komponenterna inte själva sätter + * stil på — rubriker fångas annars av värdapplikationens h1–h6-regel. + */ +.alva-yta, +.alva-yta h1, +.alva-yta h2, +.alva-yta h3, +.alva-yta h4, +.alva-yta h5, +.alva-yta h6, +.alva-yta button, +.alva-yta input, +.alva-yta select, +.alva-yta textarea { + font-family: + "DIN 2014", + "FF DIN", + "IBM Plex Sans", + "Inter", + "Helvetica Neue", + Helvetica, + Arial, + system-ui, + sans-serif; +} + +/* Siffror står i kolumn. En beteckning jämförs oftare än den läses. */ +.alva-yta { + font-variant-numeric: tabular-nums; +} + +.alva-yta .font-mono { + font-family: + ui-monospace, + "IBM Plex Mono", + "SF Mono", + "Cascadia Mono", + Menlo, + Consolas, + "Liberation Mono", + monospace; +} + @layer utilities { .animate-fade-up { animation: fadeUp 0.8s ease-out forwards; diff --git a/felsokning/app/src/pages/alva/Ram.tsx b/felsokning/app/src/pages/alva/Ram.tsx index f9b91dd..d04a9a0 100644 --- a/felsokning/app/src/pages/alva/Ram.tsx +++ b/felsokning/app/src/pages/alva/Ram.tsx @@ -28,7 +28,9 @@ export function Ram({ children, portal = false }: { children: ReactNode; portal? const lankar = portal ? PORTAL : PUBLIKT; return ( -
+ // `alva-yta` bär typografin ur ALVA-SPEC-001 och håller den skild + // från värdapplikationens antikva. Se src/index.css. +