From 9742c699f18336fea9fb88e08c53867b1094f53e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 05:26:15 +0000 Subject: [PATCH 1/5] Bring the web app in line with the website's design language Headlines in DM Sans 400 with tight tracking, one navy (#14243b), navy pill buttons (light pills in dark mode), the website's white highlight behind Home's amount, uppercase 12px labels and 24px surface corners. Sage stays for settled states. Most of it sits in styles/harmony.css. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01HcVKDmy3nYR8taPWrTXANu --- apps/web/index.html | 2 +- apps/web/public/manifest.webmanifest | 2 +- apps/web/src/screens/Hub.css | 2 +- apps/web/src/styles/calendar-date.css | 2 +- apps/web/src/styles/design-system.css | 9 +- apps/web/src/styles/harmony.css | 127 ++++++++++++++++++++++++++ apps/web/src/styles/index.css | 1 + apps/web/src/styles/shared.css | 10 +- apps/web/tests/design-tokens.test.ts | 6 +- apps/web/tests/stylesheets.test.ts | 5 +- 10 files changed, 149 insertions(+), 17 deletions(-) create mode 100644 apps/web/src/styles/harmony.css diff --git a/apps/web/index.html b/apps/web/index.html index 174ac66c..8eccca77 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -6,7 +6,7 @@ - + Commune h2, +.ops-board-head > span, +.a-content :is(.a-panel, .a-card) h2, +.c-home-head h2, +.c-hub .c-hub-identity h2 { + font-family: var(--font-display); + font-weight: 400; +} +.a-window-bar h2, +.c-product-dialog h2 { + font-size: 22px; + letter-spacing: -0.03em; +} +.a-content :is(.a-panel, .a-card) h2, +.c-home-head h2, +.ops-board-head > span { + font-size: 20px; + letter-spacing: -0.025em; +} +.c-hub .c-hub-identity h2 { + letter-spacing: -0.04em; +} +.ops-yours > h2 { + font-size: 30px; + letter-spacing: -0.035em; +} +.c-home-display { + font-weight: 400; + letter-spacing: -0.04em; +} +.c-home-square .c-home-display { + letter-spacing: -0.045em; +} + +/* The website's white highlight, behind the amounts Home opens on. It + carries its own ink, so it reads on the phone's navy band too. */ +.c-home-standing .c-home-display em { + padding: 0 0.16em 0.04em; + border-radius: 12px; + background: var(--home-surface); + color: var(--home-ink); + -webkit-box-decoration-break: clone; + box-decoration-break: clone; +} + +/* The website's small label: uppercase, 12px, spaced. */ +.c-home-over, +.c-home-group h3 { + font-size: 12px; + font-weight: 500; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +/* Buttons: round, and navy when filled. */ +.a-body :is(.a-btn, .c-home-btn, .ops-add, .c-hub-button) { + border-radius: var(--radius-pill); +} +.a-body .a-btn:not(.ghost, .danger, .nudge), +.a-body .ops-add, +.a-body :is(.a-seg, .a-note-types) button.is-on, +.a-body .c-split-methods button[aria-pressed=true] { + background: var(--action); + color: var(--on-action); +} +.a-body .a-btn:not(.ghost, .danger, .nudge):hover:not(:disabled), +.a-body .ops-add:hover:not(:disabled) { + background: var(--action-hover); +} +.c-home { + --home-action: var(--action); + --home-action-hover: var(--action-hover); + --home-on-action: var(--on-action); +} + +/* Rounder cards, as on the website. */ +.a-card { + border-radius: var(--radius-surface); +} + +/* This Hub: the same pills, navy action and display headings. Links that + used the green action colour keep green for text, as on the website. */ +.c-hub { + --hub-action: var(--action); + --hub-action-text: var(--on-action); + --hub-action-hover: var(--action-hover); +} +.c-hub-link, +.c-hub-note-row:hover strong { + color: var(--text-green); +} +.c-hub :is(.c-hub-attention-end button, .c-hub-invite, .c-hub-settings) { + border-radius: var(--radius-pill); +} +.c-hub-section-title { + font-family: var(--font-display); + font-weight: 400; + font-size: 20px; + letter-spacing: -0.025em; +} diff --git a/apps/web/src/styles/index.css b/apps/web/src/styles/index.css index 2f580294..9aca9c7e 100644 --- a/apps/web/src/styles/index.css +++ b/apps/web/src/styles/index.css @@ -20,5 +20,6 @@ @import "./overrides.css" layer(overrides); @import "./design-system.css" layer(overrides); @import "./motion.css" layer(overrides); +@import "./harmony.css" layer(overrides); /* Font faces only, which layers do not affect. */ @import "./fonts.css"; diff --git a/apps/web/src/styles/shared.css b/apps/web/src/styles/shared.css index 199f3e14..fb4f6537 100644 --- a/apps/web/src/styles/shared.css +++ b/apps/web/src/styles/shared.css @@ -15,9 +15,9 @@ --focus-ring: var(--sage); --danger: #9b2c2c; --danger-soft: #fde8e4; - --navy: #1a1e2b; - --navy-2: #1f2330; - --navy-3: #21262f; + --navy: #14243b; + --navy-2: #1b2d47; + --navy-3: #203450; --ink: #171b24; --ink-soft: #667085; --peach: #efdccf; @@ -33,11 +33,13 @@ --shadow-sm: 0 1px 3px rgba(23, 27, 36, 0.06), 0 1px 2px rgba(23, 27, 36, 0.04); --shadow: 0 4px 12px rgba(23, 27, 36, 0.07), 0 1px 3px rgba(23, 27, 36, 0.05); --radius-control: 9px; - --radius-surface: 15px; + --radius-surface: 24px; --radius-pill: 999px; --radius: var(--radius-surface); --radius-sm: var(--radius-control); --font: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + /* The website's display face, for headlines (harmony.css). */ + --font-display: "DM Sans", var(--font); /* Motion (design panel, 11 October 2026, medium direction). Every duration and curve in the app is one of these. Things arrive over the medium time and leave over the short one; the long one is for the all-square diff --git a/apps/web/tests/design-tokens.test.ts b/apps/web/tests/design-tokens.test.ts index 4ff6311d..aadedb9f 100644 --- a/apps/web/tests/design-tokens.test.ts +++ b/apps/web/tests/design-tokens.test.ts @@ -27,8 +27,8 @@ describe("shared page header contract", () => { expect(styles.hub).not.toMatch(/\.hub-editorial\s+\.a-header(?:\b|[-\s])/); expect(declarations("app", ".a-header")).toContain("padding: 12px 28px;"); expect(declarations("app", ".a-header")).toContain("color: var(--ink);"); - expect(declarations("primitives", ".a-header-title h1")).toContain("font-size: 21px;"); - expect(declarations("primitives", ".a-header-title h1")).toContain("font-weight: 550;"); + expect(declarations("primitives", ".a-header-title h1")).toContain("font-size: 24px;"); + expect(declarations("primitives", ".a-header-title h1")).toContain("font-weight: 400;"); }); }); @@ -46,7 +46,7 @@ describe("Settle share action alignment", () => { describe("shared corner contracts", () => { it("defines a single control/surface family with legacy aliases", () => { expect(styles.shared).toContain("--radius-control: 9px;"); - expect(styles.shared).toContain("--radius-surface: 15px;"); + expect(styles.shared).toContain("--radius-surface: 24px;"); expect(styles.shared).toContain("--radius: var(--radius-surface);"); expect(styles.shared).toContain("--radius-sm: var(--radius-control);"); expect(styles.primitives).not.toMatch(/--radius(?:-sm)?:\s*\d/); diff --git a/apps/web/tests/stylesheets.test.ts b/apps/web/tests/stylesheets.test.ts index 341ea5fc..cf0a9453 100644 --- a/apps/web/tests/stylesheets.test.ts +++ b/apps/web/tests/stylesheets.test.ts @@ -54,11 +54,12 @@ describe("cascade layers", () => { '@import "./overrides.css" layer(overrides);', '@import "./design-system.css" layer(overrides);', '@import "./motion.css" layer(overrides);', + '@import "./harmony.css" layer(overrides);', '@import "./fonts.css";', ]); expect(stylesheets(resolve(src, "styles")).sort()).toEqual([ "styles/app.css", "styles/auth.css", "styles/calendar-date.css", "styles/design-system.css", - "styles/fonts.css", "styles/index.css", "styles/legal.css", "styles/motion.css", "styles/overrides.css", "styles/shared.css", + "styles/fonts.css", "styles/harmony.css", "styles/index.css", "styles/legal.css", "styles/motion.css", "styles/overrides.css", "styles/shared.css", ]); expect(topLevel(read("styles/fonts.css")).every((block) => block === "@font-face")).toBe(true); }); @@ -95,7 +96,7 @@ describe("colours", () => { const fixed = new Map([...definitions] .filter(([, values]) => values.length === 1 && /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(values[0])) .map(([name, [value]]) => [hex(value), name])); - expect(fixed.get("1a1e2b")).toBe("--navy"); + expect(fixed.get("14243b")).toBe("--navy"); expect(fixed.get("2d6a4f")).toBe("--sage"); const literals = css.flatMap(([path, text]) => [...text.replace(/--[\w-]+\s*:[^;}]+/g, "").matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)] .filter(([match]) => fixed.has(hex(match))) From 29e1ca4a2e05a1c42dc3b042aae40e0ba7087248 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 05:48:02 +0000 Subject: [PATCH 2/5] Keep the app's green for buttons, with the website's round shape Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01HcVKDmy3nYR8taPWrTXANu --- apps/web/src/styles/harmony.css | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/web/src/styles/harmony.css b/apps/web/src/styles/harmony.css index f8d943d1..0e452768 100644 --- a/apps/web/src/styles/harmony.css +++ b/apps/web/src/styles/harmony.css @@ -1,25 +1,24 @@ /* * Harmony with the website (12 October 2026). The marketing site leads and * the app borrows its signatures: light DM Sans headlines with tight - * tracking, one navy (#14243b), navy pill buttons, the white highlight + * tracking, one navy (#14243b), round sage buttons, the white highlight * behind the amount, small uppercase labels and rounder cards. Inter stays * for rows, figures and forms. Sage stays for what is settled and good - * (progress, "settled" tags); navy is what you press. + * (Edem kept the green and took the website's round shape, 12 October). * Plan: https://claude.ai/artifact/K1Wao31fQRzg4fPFNtFXw2 * In the overrides layer, after the design-language primitives, so one file * holds the whole change. */ :root { - --action: var(--navy); - --action-hover: #0d1a2c; + --action: var(--sage); + --action-hover: #24583f; --on-action: #ffffff; } -/* On a dark page the site's own buttons on navy are light pills. */ .a-body.is-dark { - --action: #f5f1ea; - --action-hover: #ffffff; - --on-action: var(--navy); + --action: #7cc39f; + --action-hover: #95d2b2; + --on-action: #0c1912; } /* Headlines: the website's light display type. */ @@ -79,7 +78,7 @@ text-transform: uppercase; } -/* Buttons: round, and navy when filled. */ +/* Buttons: the website's round shape, in the app's green. */ .a-body :is(.a-btn, .c-home-btn, .ops-add, .c-hub-button) { border-radius: var(--radius-pill); } @@ -105,7 +104,7 @@ border-radius: var(--radius-surface); } -/* This Hub: the same pills, navy action and display headings. Links that +/* This Hub: the same green pills and display headings. Links that used the green action colour keep green for text, as on the website. */ .c-hub { --hub-action: var(--action); From 095eccce148fcd2663809694549e06156c6c6880 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 05:55:56 +0000 Subject: [PATCH 3/5] Phone app: round buttons in the same green Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01HcVKDmy3nYR8taPWrTXANu --- apps/native/app/(tabs)/expenses.tsx | 4 ++-- apps/native/src/ui/kit.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/native/app/(tabs)/expenses.tsx b/apps/native/app/(tabs)/expenses.tsx index 5174e6ce..81bb1b73 100644 --- a/apps/native/app/(tabs)/expenses.tsx +++ b/apps/native/app/(tabs)/expenses.tsx @@ -31,11 +31,11 @@ export default function Expenses() { - + {(["all", "open", "settled"] as Filter[]).map((value) => { const on = filter === value; return setFilter(value)} - style={{ height: 32, paddingHorizontal: 14, borderRadius: 8, justifyContent: "center", backgroundColor: on ? c.frame : "transparent" }}> + style={{ height: 32, paddingHorizontal: 14, borderRadius: radius.pill, justifyContent: "center", backgroundColor: on ? c.frame : "transparent" }}> {value[0].toUpperCase() + value.slice(1)} ; })} diff --git a/apps/native/src/ui/kit.tsx b/apps/native/src/ui/kit.tsx index 38c44c56..398f3124 100644 --- a/apps/native/src/ui/kit.tsx +++ b/apps/native/src/ui/kit.tsx @@ -48,7 +48,7 @@ export function Button({ label, onPress, variant = "primary", size = "md", block disabled={disabled || busy} onPress={() => { tap(); onPress?.(); }} style={({ pressed }) => [{ - height, paddingHorizontal: size === "sm" ? 12 : size === "lg" ? 20 : 16, borderRadius: radius.control, backgroundColor: bg, + height, paddingHorizontal: size === "sm" ? 14 : size === "lg" ? 22 : 18, borderRadius: radius.pill, backgroundColor: bg, flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 8, alignSelf: block ? "stretch" : "flex-start", opacity: disabled ? 0.45 : pressed ? 0.85 : 1, }, variant === "secondary" || variant === "danger" ? { borderWidth: 1, borderColor: variant === "danger" ? c.late : c.outline } : null]}> From e09fb6f979fbc4079f5f38db1575b86d1e8a647b Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 00:43:49 +0000 Subject: [PATCH 4/5] Home: sentence and next step share one pale green panel on wider screens Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01HcVKDmy3nYR8taPWrTXANu --- apps/web/src/styles/harmony.css | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/web/src/styles/harmony.css b/apps/web/src/styles/harmony.css index 0e452768..8c1318ee 100644 --- a/apps/web/src/styles/harmony.css +++ b/apps/web/src/styles/harmony.css @@ -124,3 +124,23 @@ font-size: 20px; letter-spacing: -0.025em; } + +/* Home on wider screens: the sentence and the next step share one pale + green panel (the landing page's green), the white next step held inside + it, so the two read as one shape, as the navy band and the next step do + on a phone (Edem, 13 October). */ +.c-home { + --home-panel: #dce8d3; +} +.a-body.is-dark .c-home { + --home-panel: #253b34; +} +@media (min-width: 561px) { + .c-home-top { + gap: 16px; + padding: 30px 16px 16px; + border-radius: var(--radius-surface); + background: var(--home-panel); + } + .c-home-top > .c-home-standing { padding: 0 16px 10px; } +} From 4d8bc60b70d6d08861ceae37aa56a90356089c38 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 01:23:51 +0000 Subject: [PATCH 5/5] Home: even spacing inside the green panel The space above the date and the space between the sentence and the next-step card are now the same (28px). Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01HcVKDmy3nYR8taPWrTXANu --- apps/web/src/styles/harmony.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/src/styles/harmony.css b/apps/web/src/styles/harmony.css index 8c1318ee..d2d31679 100644 --- a/apps/web/src/styles/harmony.css +++ b/apps/web/src/styles/harmony.css @@ -137,10 +137,10 @@ } @media (min-width: 561px) { .c-home-top { - gap: 16px; - padding: 30px 16px 16px; + gap: 0; + padding: 28px 16px 16px; border-radius: var(--radius-surface); background: var(--home-panel); } - .c-home-top > .c-home-standing { padding: 0 16px 10px; } + .c-home-top > .c-home-standing { padding: 0 16px 28px; } }