Brand Kit Page & Canonical Design Foundation — Implementation Plan
Brand Kit Page & Canonical Design Foundation — Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Ship a public plings.io/brand page where print vendors and partners can preview and download the official Plings logos, colours, typography, font kit and brand guidelines, and make docs/brand/design-system.md the documented canonical source of colour/typography for web and iOS.
Architecture: Static assets committed under public/static/brand/ (served by Vercel CDN). A typed manifest (src/data/brandAssets.ts) drives a public route /brand (src/pages/Brand.tsx) composed of small presentational components under src/components/brand/. No auth, no GraphQL, no backend — downloads are plain <a href download>.
Tech Stack: React + TypeScript + Vite, Tailwind, shadcn/ui (Button, Card, Tabs, Badge, Separator, Accordion), sonner for toasts, lucide-react icons, react-router-dom.
Spec: docs/specs/2026-07-04-brand-kit-page-design.md
Testing note: Plings-Web has no unit-test runner (per CLAUDE.md). The verification gate for every task is npx tsc --noEmit + npm run build, plus manual preview checks where a task is visual. Tasks are TDD-adapted accordingly.
File structure
public/static/brand/
logos/{symbol,horizontal,vertical,full}/… # Task 1 (import)
guidelines/Plings-brand-guidelines.{pdf,ai,eps} # Task 1
stationery/Plings_letterhead.{pdf,ai,eps,jpg} # Task 1
fonts/Poppins/*.ttf, Poppins.zip, OFL.txt # Task 1
src/data/brandAssets.ts # Task 2 (typed manifest)
src/pages/Brand.tsx # Task 3 (route target, composes sections)
src/components/brand/LogoGallery.tsx # Task 4
src/components/brand/ColorPalette.tsx # Task 5
src/components/brand/Typography.tsx # Task 6
src/components/brand/FontKit.tsx # Task 7
src/components/brand/Guidelines.tsx # Task 8
src/App.tsx # Task 3 (add route)
src/components/Footer.tsx # Task 9 (add link)
docs/brand/design-system.md # Task 10 (canonical update)
docs/use-cases/brand-kit.md # Task 11
docs/flows/brand-kit.md, docs/flows/README.md # Task 11
Plings-Web/internal/decisions/ADR-xxxx + INDEX.md # Task 11
ROADMAP.md # Task 11
Task 1: Import & organize brand assets
Depends on: Paul having downloaded the “Plings Branding” Drive folder as a zip. Confirm the actual path at execution time (likely ~/Downloads/Plings Branding-*.zip or an unzipped folder).
Files:
-
Create:
public/static/brand/{logos,guidelines,stationery,fonts}/… -
Step 1: Confirm the source path
Ask Paul for the downloaded zip/folder path. Verify it exists and list it:
SRC="$HOME/Downloads/Plings Branding" # adjust to the real path; unzip first if it's a .zip
ls -R "$SRC" | head -60
Expected: the logo/, brand guidelines/, stationary/ subfolders with the files seen in Drive.
- Step 2: Create destination folders
cd /Users/paul/Documents/GitHub/Plings/Plings-worktrees/Plings-Web/brand-kit
mkdir -p public/static/brand/logos/{symbol,horizontal,vertical,full} \
public/static/brand/{guidelines,stationery} \
public/static/brand/fonts/Poppins
- Step 3: Copy logos (exclude personal cards + Grönteknik)
Copy each logo file into its variant folder. Exclude Grönteknik_web.png and everything under stationary/ named *bc-* (business cards).
L="$SRC/logo"
# symbol (+ rounded)
cp "$L"/plings_symbol.{png,jpg,ai,eps} "$L"/plings_symbol-black.{png,jpg,ai,eps} \
"$L"/plings_symbol-white.{png,jpg,ai,eps} "$L"/plings_symbol_rounded.png \
"$L"/plings_symbol_roundedBG.png public/static/brand/logos/symbol/
# horizontal
cp "$L"/plings_logo-horizontal.{png,jpg,ai,eps} "$L"/plings_logo-horizontal-black.{png,jpg,ai,eps} \
"$L"/plings_logo-horizontal-white.{png,jpg,ai,eps} public/static/brand/logos/horizontal/
# vertical
cp "$L"/plings_logo-vertical.{png,jpg,ai,eps} "$L"/plings_logo-vertical-black.{png,jpg,ai,eps} \
"$L"/plings_logo-vertical-white.{png,jpg,ai,eps} public/static/brand/logos/vertical/
# full lockup master (only full has a PDF)
cp "$L"/plings.{ai,eps,pdf} public/static/brand/logos/full/
Note: skip .psd sources (editing-only, large — backlog). If any filename differs, adjust; do not invent files.
- Step 4: Copy guidelines and letterhead
cp "$SRC/brand guidelines"/Plings-brand-guidelines.{pdf,ai,eps} public/static/brand/guidelines/
cp "$SRC/stationary"/Plings_letterhead.{pdf,ai,eps,jpg} public/static/brand/stationery/
- Step 5: Assemble the font kit
Poppins TTFs already live in the repo under docs/brand/fonts/Poppins/. Copy them to the served location, drop the license, and zip the family:
cp docs/brand/fonts/Poppins/*.ttf public/static/brand/fonts/Poppins/
# OFL text — write the standard SIL Open Font License 1.1 header for Poppins (Indian Type Foundry et al.)
# Source it from the Poppins repo LICENSE if present in the download; otherwise create OFL.txt with the OFL 1.1 text.
(cd public/static/brand/fonts && zip -r Poppins.zip Poppins > /dev/null && ls -la Poppins.zip)
If OFL.txt is not available in the download, create public/static/brand/fonts/OFL.txt containing the SIL Open Font License 1.1 full text with the Poppins copyright line.
- Step 6: Verify the tree and file types
find public/static/brand -type f | sort
file public/static/brand/logos/symbol/plings_symbol.png # → PNG image data
file public/static/brand/guidelines/Plings-brand-guidelines.pdf # → PDF document
du -sh public/static/brand
Expected: PNG/JPG/AI/EPS/PDF/TTF/zip as intended; no .psd, no Grönteknik*, no *bc-*. Confirm total size is reasonable (~15–25 MB without EPS-heavy PSDs).
- Step 7: Commit
git add public/static/brand
git commit -m "feat(brand): import logo set, guidelines, letterhead and Poppins font kit"
Task 2: Typed asset manifest
Files:
-
Create:
src/data/brandAssets.ts -
Step 1: Write the manifest module
Paths are absolute-from-web-root (files served from public/). Only reference files that Task 1 actually produced.
// src/data/brandAssets.ts
export interface AssetFile {
format: 'PNG' | 'JPG' | 'PDF' | 'AI' | 'EPS';
src: string;
}
export interface LogoVariant {
label: 'Standard' | 'Black' | 'White';
/** PNG shown as the on-page preview for this variant */
preview: string;
/** True when the artwork is light and needs a dark surface to be visible */
needsDarkSurface?: boolean;
files: AssetFile[];
}
export interface LogoAsset {
id: string;
name: string;
variants: LogoVariant[];
}
const base = '/static/brand';
const variant = (
label: LogoVariant['label'],
stem: string,
needsDarkSurface = false,
): LogoVariant => ({
label,
preview: `${base}/${stem}.png`,
needsDarkSurface,
files: [
{ format: 'PNG', src: `${base}/${stem}.png` },
{ format: 'JPG', src: `${base}/${stem}.jpg` },
{ format: 'AI', src: `${base}/${stem}.ai` },
{ format: 'EPS', src: `${base}/${stem}.eps` },
],
});
export const logos: LogoAsset[] = [
{
id: 'horizontal',
name: 'Horizontal logo',
variants: [
variant('Standard', 'logos/horizontal/plings_logo-horizontal'),
variant('Black', 'logos/horizontal/plings_logo-horizontal-black'),
variant('White', 'logos/horizontal/plings_logo-horizontal-white', true),
],
},
{
id: 'vertical',
name: 'Vertical logo',
variants: [
variant('Standard', 'logos/vertical/plings_logo-vertical'),
variant('Black', 'logos/vertical/plings_logo-vertical-black'),
variant('White', 'logos/vertical/plings_logo-vertical-white', true),
],
},
{
id: 'symbol',
name: 'Symbol',
variants: [
variant('Standard', 'logos/symbol/plings_symbol'),
variant('Black', 'logos/symbol/plings_symbol-black'),
variant('White', 'logos/symbol/plings_symbol-white', true),
],
},
];
/** Full lockup master files (vector only; symbol+wordmark). */
export const fullLockup: AssetFile[] = [
{ format: 'AI', src: `${base}/logos/full/plings.ai` },
{ format: 'EPS', src: `${base}/logos/full/plings.eps` },
{ format: 'PDF', src: `${base}/logos/full/plings.pdf` },
];
export interface BrandColor {
name: string;
hex: string;
rgb: string;
cmyk: string;
token: string; // Tailwind token it maps to
}
export const colors: BrandColor[] = [
{ name: 'Dark teal', hex: '#00695C', rgb: '0, 105, 92', cmyk: '100, 0, 12, 58', token: 'primary.dark' },
{ name: 'Teal', hex: '#009688', rgb: '0, 150, 136', cmyk: '100, 0, 9, 41', token: 'primary' },
{ name: 'Green', hex: '#8BC34A', rgb: '139, 195, 74', cmyk: '28, 0, 62, 23', token: 'secondary' },
{ name: 'Lime', hex: '#DCE775', rgb: '220, 231, 117', cmyk: '4, 0, 49, 9', token: 'accent' },
{ name: 'Dark slate', hex: '#37474F', rgb: '55, 71, 79', cmyk: '30, 10, 0, 69', token: 'text' },
];
export interface FontWeight {
label: string; // 'Light 300'
src: string;
}
const poppins = (name: string) => `${base}/fonts/Poppins/Poppins-${name}.ttf`;
export const fontWeights: FontWeight[] = [
{ label: 'Thin 100', src: poppins('Thin') },
{ label: 'ExtraLight 200', src: poppins('ExtraLight') },
{ label: 'Light 300', src: poppins('Light') },
{ label: 'Regular 400', src: poppins('Regular') },
{ label: 'Medium 500', src: poppins('Medium') },
{ label: 'SemiBold 600', src: poppins('SemiBold') },
{ label: 'Bold 700', src: poppins('Bold') },
{ label: 'ExtraBold 800', src: poppins('ExtraBold') },
{ label: 'Black 900', src: poppins('Black') },
];
export const fontKitZip = `${base}/fonts/Poppins.zip`;
export const fontLicense = `${base}/fonts/OFL.txt`;
export const guidelinesPdf = `${base}/guidelines/Plings-brand-guidelines.pdf`;
export const letterhead: AssetFile[] = [
{ format: 'PDF', src: `${base}/stationery/Plings_letterhead.pdf` },
{ format: 'AI', src: `${base}/stationery/Plings_letterhead.ai` },
{ format: 'EPS', src: `${base}/stationery/Plings_letterhead.eps` },
];
- Step 2: Type-check
Run: npx tsc --noEmit
Expected: PASS (no errors).
- Step 3: Commit
git add src/data/brandAssets.ts
git commit -m "feat(brand): typed brand-asset manifest"
Task 3: Route + page shell
Files:
- Create:
src/pages/Brand.tsx -
Modify:
src/App.tsx(add public route, following the/aboutpattern) - Step 1: Create the page shell with section placeholders
// src/pages/Brand.tsx
import React from 'react';
import Navigation from '@/components/Navigation';
import Footer from '@/components/Footer';
import { Button } from '@/components/ui/button';
import { Download } from 'lucide-react';
import { guidelinesPdf } from '@/data/brandAssets';
import LogoGallery from '@/components/brand/LogoGallery';
import ColorPalette from '@/components/brand/ColorPalette';
import Typography from '@/components/brand/Typography';
import FontKit from '@/components/brand/FontKit';
import Guidelines from '@/components/brand/Guidelines';
const Section = ({ id, title, children }: { id: string; title: string; children: React.ReactNode }) => (
<section id={id} className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-12 border-t border-border first:border-t-0">
<h2 className="text-2xl font-bold mb-8 text-foreground">{title}</h2>
{children}
</section>
);
const BrandPage = () => (
<div className="min-h-screen">
<Navigation />
<header className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 pt-16 pb-8">
<h1 className="text-4xl font-bold text-foreground mb-4">Plings Brand Kit</h1>
<p className="text-lg text-muted-foreground max-w-2xl">
Official logos, colours, typography and guidelines. Free to download for partners
and print vendors — please follow the usage rules below.
</p>
<Button asChild className="mt-6">
<a href={guidelinesPdf} download>
<Download className="w-4 h-4 mr-2" /> Download guidelines (PDF)
</a>
</Button>
</header>
<main>
<Section id="logos" title="Logos"><LogoGallery /></Section>
<Section id="colors" title="Colours"><ColorPalette /></Section>
<Section id="typography" title="Typography"><Typography /></Section>
<Section id="fonts" title="Font kit"><FontKit /></Section>
<Section id="guidelines" title="Usage guidelines"><Guidelines /></Section>
</main>
<Footer />
</div>
);
export default BrandPage;
- Step 2: Create temporary stub components so the page compiles
Create each of these five files with a one-line stub export default () => null; so Task 3 builds independently; Tasks 4–8 replace them:
src/components/brand/{LogoGallery,ColorPalette,Typography,FontKit,Guidelines}.tsx
// e.g. src/components/brand/LogoGallery.tsx
const LogoGallery = () => null;
export default LogoGallery;
- Step 3: Add the route in
src/App.tsx
Next to <Route path="/about" element={<About />} /> (~line 88), add:
import Brand from "./pages/Brand";
// …
<Route path="/brand" element={<Brand />} />
(Place the import beside the other page imports at the top of the file.)
- Step 4: Type-check and build
Run: npx tsc --noEmit && npm run build
Expected: PASS.
- Step 5: Preview
Start the dev server (npm run dev:local or preview_start) and load /brand. Expect the hero, five section headings and the guidelines PDF button. Verify the PDF downloads.
- Step 6: Commit
git add src/pages/Brand.tsx src/components/brand src/App.tsx
git commit -m "feat(brand): /brand route and page shell with section stubs"
Task 4: LogoGallery
Files:
-
Modify:
src/components/brand/LogoGallery.tsx -
Step 1: Implement the gallery
One card per logo, a variant selector (Standard/Black/White) that swaps the preview and its download set, a light/dark preview surface toggle, and a per-format download row. Plus a “Full lockup (vector)” card for fullLockup.
// src/components/brand/LogoGallery.tsx
import React, { useState } from 'react';
import { Card } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Download, Sun, Moon } from 'lucide-react';
import { logos, fullLockup, type LogoAsset } from '@/data/brandAssets';
const LogoCard = ({ asset }: { asset: LogoAsset }) => {
const [variantIdx, setVariantIdx] = useState(0);
const [dark, setDark] = useState(false);
const variant = asset.variants[variantIdx];
return (
<Card className="p-4 flex flex-col gap-3">
<div
className={`flex items-center justify-center rounded-md h-40 p-6 ${dark ? 'bg-gray-900' : 'bg-gray-50'}`}
>
<img src={variant.preview} alt={`${asset.name} — ${variant.label}`} className="max-h-full max-w-full object-contain" />
</div>
<div className="flex items-center justify-between">
<div className="flex gap-1">
{asset.variants.map((v, i) => (
<Button key={v.label} size="sm" variant={i === variantIdx ? 'default' : 'outline'} onClick={() => setVariantIdx(i)}>
{v.label}
</Button>
))}
</div>
<Button size="icon" variant="ghost" aria-label="Toggle preview background" onClick={() => setDark((d) => !d)}>
{dark ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
</Button>
</div>
<div className="font-semibold text-sm text-foreground">{asset.name}</div>
<div className="flex flex-wrap gap-2">
{variant.files.map((f) => (
<Button key={f.format} asChild size="sm" variant="secondary">
<a href={f.src} download>
<Download className="w-3 h-3 mr-1" />{f.format}
</a>
</Button>
))}
</div>
</Card>
);
};
const LogoGallery = () => (
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{logos.map((asset) => <LogoCard key={asset.id} asset={asset} />)}
<Card className="p-4 flex flex-col gap-3">
<div className="flex items-center justify-center rounded-md h-40 p-6 bg-gray-50">
<img src="/static/brand/logos/horizontal/plings_logo-horizontal.png" alt="Full lockup" className="max-h-full max-w-full object-contain" />
</div>
<div className="font-semibold text-sm text-foreground">Full lockup (vector master)</div>
<div className="flex flex-wrap gap-2">
{fullLockup.map((f) => (
<Button key={f.format} asChild size="sm" variant="secondary">
<a href={f.src} download><Download className="w-3 h-3 mr-1" />{f.format}</a>
</Button>
))}
</div>
</Card>
</div>
);
export default LogoGallery;
- Step 2: Type-check + build
Run: npx tsc --noEmit && npm run build → PASS.
- Step 3: Preview
Reload /brand. Verify: three logo cards + full-lockup card; variant buttons swap the image and downloads; background toggle makes the white variant visible; each format link downloads the right file.
- Step 4: Commit
git add src/components/brand/LogoGallery.tsx
git commit -m "feat(brand): logo gallery with variant + format downloads"
Task 5: ColorPalette
Files:
-
Modify:
src/components/brand/ColorPalette.tsx -
Step 1: Implement swatches with copy-to-clipboard
// src/components/brand/ColorPalette.tsx
import React from 'react';
import { Card } from '@/components/ui/card';
import { toast } from 'sonner';
import { colors } from '@/data/brandAssets';
const copy = (label: string, value: string) => {
navigator.clipboard.writeText(value).then(() => toast.success(`Copied ${label}: ${value}`));
};
const ColorPalette = () => (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{colors.map((c) => (
<Card key={c.hex} className="overflow-hidden">
<div className="h-24" style= />
<div className="p-4 space-y-1 text-sm">
<div className="font-semibold text-foreground">{c.name} <span className="text-muted-foreground font-normal">({c.token})</span></div>
<button className="block hover:underline" onClick={() => copy('HEX', c.hex)}>HEX {c.hex}</button>
<button className="block hover:underline" onClick={() => copy('RGB', c.rgb)}>RGB {c.rgb}</button>
<button className="block hover:underline" onClick={() => copy('CMYK', c.cmyk)}>CMYK {c.cmyk}</button>
</div>
</Card>
))}
</div>
);
export default ColorPalette;
-
Step 2: Type-check + build →
npx tsc --noEmit && npm run build→ PASS. -
Step 3: Preview
Reload /brand#colors. Verify five swatches show correct colours; clicking HEX/RGB/CMYK copies the value and shows a toast.
- Step 4: Commit
git add src/components/brand/ColorPalette.tsx
git commit -m "feat(brand): colour palette with copy-to-clipboard"
Task 6: Typography
Files:
-
Modify:
src/components/brand/Typography.tsx -
Step 1: Implement the specimen
Poppins is already the app’s default font (font-poppins); render Bold + Light samples.
// src/components/brand/Typography.tsx
import React from 'react';
import { Card } from '@/components/ui/card';
const Typography = () => (
<div className="space-y-6">
<Card className="p-6">
<div className="text-xs uppercase tracking-wide text-muted-foreground mb-2">Headline — Poppins Bold (700)</div>
<p className="font-poppins font-bold text-3xl text-foreground">The quick brown fox jumps over the lazy dog</p>
</Card>
<Card className="p-6">
<div className="text-xs uppercase tracking-wide text-muted-foreground mb-2">Body copy — Poppins Light (300)</div>
<p className="font-poppins font-light text-lg text-foreground">The quick brown fox jumps over the lazy dog — 1234567890</p>
</Card>
<p className="text-sm text-muted-foreground">
Plings uses <strong>Poppins</strong> throughout: Bold for headlines, Light for body copy. Download the full family in the Font kit below.
</p>
</div>
);
export default Typography;
- Step 2: Type-check + build → PASS.
- Step 3: Preview — reload
/brand#typography; verify Bold and Light samples render in Poppins. - Step 4: Commit
git add src/components/brand/Typography.tsx
git commit -m "feat(brand): typography specimen"
Task 7: FontKit
Files:
-
Modify:
src/components/brand/FontKit.tsx -
Step 1: Implement per-weight + zip downloads with licence note
// src/components/brand/FontKit.tsx
import React from 'react';
import { Button } from '@/components/ui/button';
import { Download } from 'lucide-react';
import { fontWeights, fontKitZip, fontLicense } from '@/data/brandAssets';
const FontKit = () => (
<div className="space-y-4">
<div className="flex flex-wrap gap-3 items-center">
<Button asChild>
<a href={fontKitZip} download><Download className="w-4 h-4 mr-2" />Download all (zip)</a>
</Button>
<a href={fontLicense} className="text-sm text-muted-foreground hover:underline" target="_blank" rel="noreferrer">
SIL Open Font License
</a>
</div>
<div className="flex flex-wrap gap-2">
{fontWeights.map((w) => (
<Button key={w.label} asChild size="sm" variant="outline">
<a href={w.src} download><Download className="w-3 h-3 mr-1" />{w.label}</a>
</Button>
))}
</div>
<p className="text-sm text-muted-foreground">
Poppins is licensed under the SIL Open Font License 1.1 and is free to use and redistribute.
</p>
</div>
);
export default FontKit;
- Step 2: Type-check + build → PASS.
- Step 3: Preview — reload
/brand#fonts; verify each weight and the zip download; the OFL link opens. - Step 4: Commit
git add src/components/brand/FontKit.tsx
git commit -m "feat(brand): downloadable Poppins font kit"
Task 8: Guidelines (structured web edition)
Files:
-
Modify:
src/components/brand/Guidelines.tsx -
Step 1: Implement the structured guidelines
Render the guidelines’ sections natively (colour/typography are covered above and not repeated). Use Accordion for the restriction rules.
// src/components/brand/Guidelines.tsx
import React from 'react';
import { Card } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Download, Check, X } from 'lucide-react';
import { guidelinesPdf } from '@/data/brandAssets';
const dos = [
'Use the symbol and wordmark together in the relationship shown.',
'The symbol may be used on its own without the wordmark.',
'Keep clear space around the logo — the margin equals the width of the "s" in "Plings".',
];
const donts = [
'Do not place the logo on a colour or image with similar contrast.',
'Do not substitute the font or use different weights.',
'Do not rotate the logo or move the symbol away from the text.',
'Do not squash or stretch the logo.',
];
const Guidelines = () => (
<div className="space-y-8">
<div className="grid gap-6 md:grid-cols-2">
<Card className="p-6">
<h3 className="font-semibold mb-2 text-foreground">Logo construction</h3>
<p className="text-sm text-muted-foreground">
The logo has two elements — the <strong>symbol</strong> and the <strong>wordmark</strong>.
Use them together as shown; the symbol can stand alone.
</p>
</Card>
<Card className="p-6">
<h3 className="font-semibold mb-2 text-foreground">Variations</h3>
<p className="text-sm text-muted-foreground">
Vertical, horizontal and symbol-only lockups. The logo-with-slogan uses Poppins Light.
</p>
</Card>
<Card className="p-6">
<h3 className="font-semibold mb-2 text-foreground">Safe zone</h3>
<p className="text-sm text-muted-foreground">
Maintain clear space around the logo. The minimum margin equals the width of the
"s" in "Plings". Keep other graphics outside this zone.
</p>
</Card>
<Card className="p-6">
<h3 className="font-semibold mb-2 text-foreground">Full guidelines</h3>
<p className="text-sm text-muted-foreground mb-3">The complete brand manual as a printable PDF.</p>
<Button asChild size="sm"><a href={guidelinesPdf} download><Download className="w-3 h-3 mr-1" />PDF</a></Button>
</Card>
</div>
<div className="grid gap-6 md:grid-cols-2">
<Card className="p-6">
<h3 className="font-semibold mb-3 text-foreground">Do</h3>
<ul className="space-y-2">
{dos.map((d) => (
<li key={d} className="flex gap-2 text-sm text-muted-foreground"><Check className="w-4 h-4 text-primary shrink-0 mt-0.5" />{d}</li>
))}
</ul>
</Card>
<Card className="p-6">
<h3 className="font-semibold mb-3 text-foreground">Don't</h3>
<ul className="space-y-2">
{donts.map((d) => (
<li key={d} className="flex gap-2 text-sm text-muted-foreground"><X className="w-4 h-4 text-destructive shrink-0 mt-0.5" />{d}</li>
))}
</ul>
</Card>
</div>
</div>
);
export default Guidelines;
- Step 2: Type-check + build → PASS.
- Step 3: Preview — reload
/brand#guidelines; verify the four info cards + Do/Don’t lists render; PDF button works. - Step 4: Commit
git add src/components/brand/Guidelines.tsx
git commit -m "feat(brand): structured web edition of the brand guidelines"
Task 9: Footer discoverability link
Files:
-
Modify:
src/components/Footer.tsx(the “Resources” section’slinksarray) -
Step 1: Add a Brand kit link
In the Resources section links array, add:
{ label: "Brand Kit", href: "/brand" },
- Step 2: Type-check + build → PASS.
- Step 3: Preview — the footer shows a “Brand Kit” link that routes to
/brand. - Step 4: Commit
git add src/components/Footer.tsx
git commit -m "feat(brand): link brand kit from the footer"
Task 10: Canonical design-foundation doc
Files:
-
Modify:
docs/brand/design-system.md -
Step 1: Update the doc
Make these changes to docs/brand/design-system.md:
- Add a timestamp header block (per CLAUDE.md doc standards) and a first line stating: “This document is the canonical source of truth for Plings colour and typography. Web (
tailwind.config.ts/index.css) and iOS must reference these values.” - Extend the “Brand Color Palette Reference” table with CMYK and HSB columns and the exact code token each maps to (values from the spec’s colour table).
- Add a “Where this is implemented” subsection linking
tailwind.config.tsprimary/secondary/accent andindex.cssHSL vars, and noting Poppins is loaded inindex.html. - Replace the stale
backend/static/logos/file-structure block with the realpublic/static/brand/layout, and link to the public/brandpage andguidelines/Plings-brand-guidelines.pdf. - Remove the mostly-completed “Implementation Notes” checklist (or trim to genuinely open items).
- Step 2: Verify no broken relative links / build
Run: npm run build (docs are not part of the Vite build, so this only re-confirms the app; the doc change is text). Visually confirm the table renders in Markdown.
- Step 3: Commit
git add docs/brand/design-system.md
git commit -m "docs(brand): make design-system.md the canonical colour/type source"
Task 11: Use-case, flow doc, ADR, ROADMAP
Files:
- Create:
docs/use-cases/brand-kit.md - Create:
docs/flows/brand-kit.md; Modify:docs/flows/README.md - Create:
Plings-Web/internal/decisions/ADR-<next>-brand-kit-hosting-and-canonical-tokens.md; Modify:Plings-Web/internal/decisions/INDEX.md -
Modify:
ROADMAP.md - Step 1: Confirm use-case intent with Paul, then write the use-case
Per CLAUDE.md the why is Paul’s to confirm. Draft docs/use-cases/brand-kit.md: actor = external print vendor / partner; need = get correct on-brand assets without contacting Plings; value = consistent brand reproduction, less back-and-forth, Drive-independent. Confirm the intent line with Paul before finalising.
- Step 2: Write the flow doc + index row
docs/flows/brand-kit.md: how the flow works now — public /brand route → manifest-driven sections → static-file downloads; links to the design-system doc (why colours/type) and the spec (history). Add a row to docs/flows/README.md for the “Brand kit” flow.
- Step 3: Write the ADR (stub) + INDEX row
Determine the next ADR number:
ls /Users/paul/Documents/GitHub/Plings/Plings-Web/internal/decisions/ | grep -E '^ADR-' | sort | tail -3
Create ADR-<next>-brand-kit-hosting-and-canonical-tokens.md (Accepted): decision = brand binaries hosted in-repo under public/static/brand/, and docs/brand/design-system.md is the canonical colour/typography source that web + iOS reference. Add the one-line INDEX.md row.
- Step 4: Update ROADMAP
Move the brand-kit item to Done with the PR ref + date; add Backlog items: SVG logos (need Illustrator export), publish PSD sources if a vendor requests, wire iOS colours to the documented tokens.
- Step 5: Commit
git add docs/use-cases/brand-kit.md docs/flows/brand-kit.md docs/flows/README.md \
/Users/paul/Documents/GitHub/Plings/Plings-Web/internal/decisions ROADMAP.md
git commit -m "docs(brand): use-case, flow doc, ADR and roadmap for the brand kit"
Task 12: Final verification & quality control
- Step 1: Full type-check + build
Run: npx tsc --noEmit && npm run build
Expected: both PASS.
- Step 2: Full preview pass
On /brand, confirm end-to-end: hero PDF button; every logo card (variant swap, dark/light surface, each format downloads a real file); colour copy works; typography renders in Poppins; every font weight + zip downloads; guidelines section reads correctly; footer link routes here. Check mobile width (preview_resize) and dark mode.
- Step 3: Spot-check downloaded files open
Download one PNG, one AI, one PDF, the font zip, and confirm each opens as the correct file type (not HTML/404).
- Step 4: quality-control-enforcer review
Dispatch the quality-control-enforcer agent over the diff (public static page, no auth/PII, but review manifest correctness, link integrity, and that no excluded assets leaked in). Address findings.
- Step 5: Push, PR, merge (per CLAUDE.md autonomous workflow)
git push -u origin task/brand-kit
gh pr create --base dev --title "Public brand kit page + canonical design foundation" --body "…"
gh pr merge --merge
Then fast-forward the local dev checkout the user builds from, and remove the worktree.
Self-review notes
- Spec coverage: public page ✔ (T3–T9), colours/type/logos/guidelines/fonts ✔ (T4–T8), assets in-repo ✔ (T1), exclusions ✔ (T1 step 3–4), canonical doc ✔ (T10), use-case/flow/ADR/roadmap ✔ (T11), SVG backlog ✔ (T11 step 4).
- Import risk: T1 depends on Paul’s local download (decided in brainstorming) — flagged, not silently assumed.
- Type consistency: manifest exports (
logos,fullLockup,colors,fontWeights,fontKitZip,fontLicense,guidelinesPdf) are defined in T2 and consumed unchanged in T3–T8.