Brand book
10 · Downloads

Everything you need to build Pantri

Real files, ready to use. Logos are outlined SVG, so they render the same everywhere. Tokens come in three shapes: JSON, plain CSS variables, and a drop-in for the existing v2 Tailwind setup.

Everything

The whole kit

Logos

Wordmark

App icons

App icon and favicon

Illustrations

Illustration kit

Tokens

Design tokens and code

Fraunces and Inter are free from Google Fonts under the SIL Open Font Licence. In Next.js, load them with next/font/google; Fraunces needs the opsz and SOFT axes.

For Pantri Dev

Migrating v2 to Hearth

Hearth keeps every v2 token name. Paste globals.hearth.css over the --v2-* blocks in apps/web/src/styles/globals.css, and every component already using bg-surface-page, text-ink, bg-action or border-hairline moves to Hearth with no class changes. Then merge tailwind.hearth.ts into theme.extend for the new tokens and the Fraunces titles.

v2 variableHearth nameLightDark
--v2-surfacePaper#FAF6F0#1A1511
--v2-surface-raisedRaised#FFFFFF#241D18
--v2-surface-sunkenSunken#F2ECE3#14100D
--v2-hairlineHairline#DED4C6#3A3029
--v2-field-edgeField edge#8E8377#8F8274
--v2-inkInk#1E1914#F6EFE6
--v2-ink-secondaryInk 2#5A5047#C9BDB0
--v2-ink-tertiaryInk 3#6B6157#A89B8C
--v2-clayClay#C4501F#E2703F
--v2-actionAction#A63E14#EE8A5C
--v2-action-pressedAction pressed#8A3310#F4A27C
--v2-on-actionOn action#FFFFFF#1E1914
--v2-cocoaCocoa#2A211B#0F0C0A
--v2-saffronSaffron#E9B44C#E9B44C
--v2-sageSage#6F8A5E#7E9A6C
--v2-favourableGood price#1F6F43#5CC48A
--v2-unfavourablePrice rise#B4342B#F08A80

Checklist

  1. Swap the --v2-* values (light and dark).
  2. Add field-edge to inputs and checkboxes; stop using hairline as a control edge.
  3. Move figures from JetBrains Mono to Inter 600 with .tabular; text-row-figure becomes 17px.
  4. Set text-screen-title in Fraunces 26/30 600; retire Bricolage everywhere.
  5. Register new text-* sizes in extendTailwindMerge (lib/utils.ts).
  6. Point apps/landing at the same tokens, and ban hex literals there too.
  7. Replace the logo, favicon and PWA icons with the files above.

tailwind.hearth.ts

// Pantri · Hearth → Tailwind theme snippet for apps/web/tailwind.config.ts
// Merge into theme.extend. Existing v2 names (surface-page, surface-raised, surface-sunken,
// hairline, ink, ink-secondary, ink-tertiary, action, favourable, unfavourable, retailer-*)
// are unchanged: their VALUES move to Hearth through globals.hearth.css. Only the keys marked
// NEW are additions. Pair with the --v2-* values in globals.hearth.css.
//
// Remember (DESIGN-V2 § foundations, point 2): every new custom text-* size must also be
// registered in extendTailwindMerge in lib/utils.ts, or cn() silently drops it.

const v2 = (name: string) => `rgb(var(--v2-${name}) / <alpha-value>)`;

export const hearthTheme = {
  colors: {
    // existing v2 names, values now Hearth
    "surface-page": v2("surface"),            // Paper   #FAF6F0
    "surface-raised": v2("surface-raised"),   // Raised  #FFFFFF
    "surface-sunken": v2("surface-sunken"),   // Sunken  #F2ECE3
    hairline: v2("hairline"),                 // Hairline #DED4C6 (decorative only)
    ink: {
      DEFAULT: v2("ink"),                     // Ink   #1E1914
      secondary: v2("ink-secondary"),         // Ink 2 #5A5047
      tertiary: v2("ink-tertiary"),           // Ink 3 #6B6157
    },
    action: {
      DEFAULT: v2("action"),                  // Action #A63E14
      pressed: v2("action-pressed"),          // NEW    #8A3310
    },
    "on-action": v2("on-action"),             // NEW    #FFFFFF (dark: #1E1914)
    favourable: v2("favourable"),             // Good price #1F6F43
    unfavourable: v2("unfavourable"),         // Price rise #B4342B
    retailer: {
      coles: v2("retailer-coles"),            // #C5141A
      woolworths: v2("retailer-woolworths"),  // #0B7A35
      aldi: v2("retailer-aldi"),              // #0B57B0
    },
    "field-edge": v2("field-edge"),           // NEW #8E8377: inputs, checkboxes (3.71:1)
    clay: v2("clay"),                         // NEW #C4501F: seed, illustration, display ≥24px only
    cocoa: v2("cocoa"),                       // NEW #2A211B: footer, cookie banner
    saffron: v2("saffron"),                   // NEW #E9B44C: fills behind ink, illustration
    sage: v2("sage"),                         // NEW #6F8A5E: illustration only
  },
  fontFamily: {
    // Replaces the Bricolage `display`/`heading` aliases. Load with next/font:
    // Fraunces({ subsets: ["latin"], axes: ["opsz", "SOFT"], variable: "--font-fraunces" })
    display: ["var(--font-fraunces, 'Fraunces')", "Georgia", "serif"],
    heading: ["var(--font-fraunces, 'Fraunces')", "Georgia", "serif"],
    sans: ["var(--font-inter, 'Inter')", "Inter", "system-ui", "sans-serif"],
    // JetBrains Mono is retired for figures: use font-sans + .tabular
  },
  fontSize: {
    "row-name": ["var(--v2-row-name-size)", { lineHeight: "1.3", fontWeight: "var(--v2-row-name-weight)" }],
    "row-figure": ["1.0625rem", { lineHeight: "1.375rem", fontWeight: "600" }], // 17px Inter tabular (was 15px mono)
    "row-meta": ["0.8125rem", { lineHeight: "1.125rem" }],                       // 13/18
    "section-label": ["0.6875rem", { lineHeight: "0.875rem", letterSpacing: "0.08em", fontWeight: "600" }],
    "screen-title": ["1.625rem", { lineHeight: "1.875rem", letterSpacing: "-0.015em", fontWeight: "600" }], // 26/30 Fraunces (was 22/700 Inter)
    "hearth-h1": ["2rem", { lineHeight: "2.25rem", letterSpacing: "-0.02em", fontWeight: "600" }],          // NEW 32/36 Fraunces
    "hearth-display": ["2.75rem", { lineHeight: "2.875rem", letterSpacing: "-0.025em", fontWeight: "600" }], // NEW 44/46 Fraunces
    "hearth-body": ["1rem", { lineHeight: "1.5rem" }],                                                       // NEW 16/24
  },
  borderRadius: {
    "hearth-sm": "6px",    // checkboxes, tags
    "hearth-md": "12px",   // buttons, inputs, cookie banner
    "hearth-lg": "20px",   // sheet top corners
  },
  minHeight: { row: "64px" },
  transitionDuration: { row: "120ms", sheet: "220ms", collapse: "300ms", hero: "400ms" },
  transitionTimingFunction: { hearth: "cubic-bezier(.2,.8,.2,1)" },
  boxShadow: {}, // Hearth uses no shadows on rows, sections or sheets. Retire card / warm / glow.
};

// Usage in tailwind.config.ts:
//   import { hearthTheme } from "./tailwind.hearth";
//   theme: { extend: { ...existing, colors: { ...existing.colors, ...hearthTheme.colors }, ... } }
//
// Screen titles: className="font-display text-screen-title [font-variation-settings:'opsz'_48,'SOFT'_100,'WONK'_0]"
// Or add once in globals.css:  .font-display { font-variation-settings: "opsz" 72, "SOFT" 100, "WONK" 0; }

globals.hearth.css

/* Pantri · Hearth → v2 token values for apps/web/src/styles/globals.css
 * Drop-in: same --v2-* names, new values, so every component already on bg-surface-page, text-ink,
 * bg-action, border-hairline etc. picks up Hearth with no class changes. New Hearth tokens are added
 * under the same --v2- namespace. Channels are space-separated RGB for rgb(var(--x) / <alpha-value>). */
@layer base {
  :root {
    --v2-surface: 250 246 240;   /* #FAF6F0 Paper */
    --v2-surface-raised: 255 255 255;   /* #FFFFFF Raised */
    --v2-surface-sunken: 242 236 227;   /* #F2ECE3 Sunken */
    --v2-hairline: 222 212 198;   /* #DED4C6 Hairline */
    --v2-field-edge: 142 131 119;   /* #8E8377 Field edge */
    --v2-ink: 30 25 20;      /* #1E1914 Ink */
    --v2-ink-secondary: 90 80 71;      /* #5A5047 Ink 2 */
    --v2-ink-tertiary: 107 97 87;     /* #6B6157 Ink 3 */
    --v2-clay: 196 80 31;     /* #C4501F Clay */
    --v2-action: 166 62 20;     /* #A63E14 Action */
    --v2-action-pressed: 138 51 16;     /* #8A3310 Action pressed */
    --v2-on-action: 255 255 255;   /* #FFFFFF On action */
    --v2-cocoa: 42 33 27;      /* #2A211B Cocoa */
    --v2-saffron: 233 180 76;    /* #E9B44C Saffron */
    --v2-sage: 111 138 94;    /* #6F8A5E Sage */
    --v2-favourable: 31 111 67;     /* #1F6F43 Good price */
    --v2-unfavourable: 180 52 43;     /* #B4342B Price rise */
    --v2-retailer-coles: 197 20 26; /* #C5141A Coles */
    --v2-retailer-woolworths: 11 122 53; /* #0B7A35 Woolworths */
    --v2-retailer-aldi: 11 87 176; /* #0B57B0 ALDI */
    --v2-row-name-size: 1.0625rem; /* 17px */
    --v2-row-name-weight: 600;
  }

  .dark {
    --v2-surface: 26 21 17;      /* #1A1511 */
    --v2-surface-raised: 36 29 24;      /* #241D18 */
    --v2-surface-sunken: 20 16 13;      /* #14100D */
    --v2-hairline: 58 48 41;      /* #3A3029 */
    --v2-field-edge: 143 130 116;   /* #8F8274 */
    --v2-ink: 246 239 230;   /* #F6EFE6 */
    --v2-ink-secondary: 201 189 176;   /* #C9BDB0 */
    --v2-ink-tertiary: 168 155 140;   /* #A89B8C */
    --v2-clay: 226 112 63;    /* #E2703F */
    --v2-action: 238 138 92;    /* #EE8A5C */
    --v2-action-pressed: 244 162 124;   /* #F4A27C */
    --v2-on-action: 30 25 20;      /* #1E1914 */
    --v2-cocoa: 15 12 10;      /* #0F0C0A */
    --v2-saffron: 233 180 76;    /* #E9B44C */
    --v2-sage: 126 154 108;   /* #7E9A6C */
    --v2-favourable: 92 196 138;    /* #5CC48A */
    --v2-unfavourable: 240 138 128;   /* #F08A80 */
    --v2-retailer-coles: 242 102 107; /* #F2666B */
    --v2-retailer-woolworths: 63 196 107; /* #3FC46B */
    --v2-retailer-aldi: 90 155 232; /* #5A9BE8 */
    --v2-row-name-size: 1.125rem; /* 18px */
    --v2-row-name-weight: 700;
  }
}