diff --git a/.ai/frontend-state.json b/.ai/frontend-state.json
index 5127d10..f9d6670 100644
--- a/.ai/frontend-state.json
+++ b/.ai/frontend-state.json
@@ -2,7 +2,7 @@
"agent": "Claude Code",
"area": "frontend",
"currentPhase": "F7 API integration (in progress)",
- "lastVerifiedTask": "TMS-F7-006b",
+ "lastVerifiedTask": "TMS-F0-013",
"nextRecommendedTask": "F7 on claude/f7-api-integration (PR #23). DONE: TMS-F7-001..004 (http foundation, per-domain data source, artworks+collections, nullable price), F7-005 (Studio on approved placements), F7-006a (canonical lineId + cart client), F7-006b (cart UI on the server cart: server totals, issue lines kept + reasons, hasIssues blocks checkout, promotion 422 vs 200-with-null). NEXT: TMS-F7-008 customer auth cutover (/api/v1/auth/*, opaque tms_session cookie) — it unblocks TMS-F7-007 saved designs (client + tests already done in lib/designs-api.ts) and makes the guest-cart merge real. BLOCKERS: (1) no live API locally — Postgres has only B1 identity tables and migrating it would disturb the parallel backend session, so everything is stub-verified; (2) TMS-FBR-020 — a cart line is pure ids and cannot be rendered from its own response, so lib/cart-view.ts joins labels from /artworks + /garments as an interim.",
"completedTasks": [
"TMS-F0-001",
@@ -17,6 +17,7 @@
"TMS-F0-010",
"TMS-F0-011",
"TMS-F0-012",
+ "TMS-F0-013",
"TMS-F1-001",
"TMS-F1-002",
"TMS-F1-003",
@@ -64,7 +65,7 @@
],
"buildStatus": "passing",
"testStatus": "passing",
- "visualRegressionStatus": "baselines-committed (4 viewports, homepage; Windows-rendered, not in CI)",
+ "visualRegressionStatus": "TMS-F0-013 logo surfaces verified at 375px and 1440px (storefront header/footer/menu, admin login/shell); prior homepage baselines remain committed",
"mockDependencies": [
"storefront:home:featuredArtworks (TMS-FBR-001)",
"storefront:/artworks listing + detail (TMS-FBR-001)",
@@ -96,7 +97,7 @@
"storefront:studio guide (/studio-guide) — deterministic mock assistant (lib/studio-guide.ts), no LLM/live tools; guardrails deflect stock/price/delivery; order-status = tool_error + retry; real assistant endpoint + tool results are backend (TMS-FBR-009)",
"storefront:loyalty & referrals (/account/loyalty) — illustrative email-derived points/tier + rewards + referral code (lib/loyalty.ts); redeem/share are preview-only; real ledger/earn/redeem + referral attribution are backend (TMS-FBR-008)"
],
- "branch": "claude/f5-post-merge",
+ "branch": "codex/fatu-logo-system",
"buildStatusNote": "F5 (growth & AI) COMPLETE — all of TMS-F5-001…010 Verified (pnpm check green). Storefront: 001 drops, 002 waitlist, 003 pre-order/made-to-order, 004 reviews, 005 community gallery, 006 artwork passport, 007 shoppable stories, 008 studio guide, 010 loyalty & referrals. Admin: 009 brand storyteller. F0–F4 Verified AND MERGED TO MAIN (2026-07-15). The F0→F4 PR stack (#4→#8) was merged bottom-up with merge commits (main HEAD e919e7e; merge commits 9599d35/190d8c7/d0201a1/f0de066/e919e7e) and all five phase branches deleted; pnpm check re-run green on the integrated main (13/13 build tasks, all unit tests, format/lint/typecheck/db:validate). Recovery note: PR #5 auto-closed when gh's --delete-branch removed its base (f0) before the auto-retarget fired; recovered by recreating the f0 branch, reopening #5, retargeting to main — thereafter each next PR was retargeted to main BEFORE merge and branches were deleted only as final cleanup. Only open item is defect TMS-F1-DEF-001 (soft 404, SEO-only). Admin Vitest 125 tests (was 116 — +9 storyteller); storefront 195 (was 89 — +24 drops, +6 waitlist, +10 fulfilment, +11 passport, +11 stories, +13 reviews, +12 community, +8 studio-guide, +11 loyalty). Note: pnpm audit 410 outage since F3-004 (this is the only failing CI 'quality' check — a retired npm endpoint, not a code issue); no new deps added.",
- "lastUpdated": "2026-07-16T03:30:00Z"
+ "lastUpdated": "2026-07-20T23:40:00+01:00"
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8359250..335f0c7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,17 @@ All notable changes to Tai Manic Studios are documented here.
The project uses a four-part release version: `major.minor.patch.micro`.
+## [0.1.1.0] - 2026-07-21
+
+### Added
+
+- Added the supplied F.A.T.U brand mark across the storefront and admin experience, including responsive navigation, authentication, and footer placements.
+- Added branded browser icons, an Apple touch icon, social sharing artwork, and an installable storefront manifest.
+
+### Changed
+
+- Replaced text-only F.A.T.U wordmarks with reusable, optimized logo components and documented the verified frontend handoff.
+
## [0.1.0.0] - 2026-07-14
### Added
diff --git a/VERSION b/VERSION
index 482e997..5cff5f1 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.0.0
+0.1.1.0
diff --git a/apps/admin/app/apple-icon.png b/apps/admin/app/apple-icon.png
new file mode 100644
index 0000000..99a5824
Binary files /dev/null and b/apps/admin/app/apple-icon.png differ
diff --git a/apps/admin/app/icon.png b/apps/admin/app/icon.png
new file mode 100644
index 0000000..ccbd3d8
Binary files /dev/null and b/apps/admin/app/icon.png differ
diff --git a/apps/admin/app/layout.tsx b/apps/admin/app/layout.tsx
index 0538b2a..92ff941 100644
--- a/apps/admin/app/layout.tsx
+++ b/apps/admin/app/layout.tsx
@@ -19,8 +19,13 @@ const sans = IBM_Plex_Sans({
});
export const metadata: Metadata = {
+ applicationName: 'F.A.T.U Admin',
title: { default: 'Admin · From Africa To You', template: '%s · F.A.T.U Admin' },
description: 'Operational console for From Africa To You.',
+ icons: {
+ icon: [{ url: '/icon.png', type: 'image/png', sizes: '512x512' }],
+ apple: [{ url: '/apple-icon.png', type: 'image/png', sizes: '180x180' }],
+ },
robots: { index: false, follow: false, nocache: true },
};
diff --git a/apps/admin/components/admin-login-form.tsx b/apps/admin/components/admin-login-form.tsx
index 60df9dd..796b4b2 100644
--- a/apps/admin/components/admin-login-form.tsx
+++ b/apps/admin/components/admin-login-form.tsx
@@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import { type AuthErrors, validateLogin } from '@/lib/admin-auth';
import { useAdminAuth } from './admin-auth-provider';
+import { BrandLogo } from './brand-logo';
const inputClass =
'h-11 w-full rounded-md border bg-surface px-3 text-sm text-ink outline-none placeholder:text-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--color-focus-ring)]';
@@ -33,7 +34,12 @@ export function AdminLoginForm() {
return (
-
F.A.T.U
+
Admin
diff --git a/apps/admin/components/admin-shell.tsx b/apps/admin/components/admin-shell.tsx
index 9e3e0b5..191c860 100644
--- a/apps/admin/components/admin-shell.tsx
+++ b/apps/admin/components/admin-shell.tsx
@@ -18,6 +18,7 @@ import Link from 'next/link';
import { usePathname, useRouter } from 'next/navigation';
import { type MouseEvent, useCallback, useEffect, useRef } from 'react';
import { useAdminAuth } from './admin-auth-provider';
+import { BrandLogo } from './brand-logo';
const NAV = [
{ href: '/', label: 'Dashboard', icon: LayoutDashboard },
@@ -63,11 +64,18 @@ function NavList({ pathname, onNavigate }: { pathname: string; onNavigate?: () =
);
}
-function BrandMark({ className }: { className?: string }) {
+function AdminBrand({ compact = false }: { compact?: boolean }) {
return (
-
- F.A.T.U
-
+
+
+
+ Admin
+
+
);
}
@@ -135,10 +143,7 @@ export function AdminShell({ children }: { children: React.ReactNode }) {
{/* Desktop sidebar — fixed in the viewport; only main content scrolls */}
@@ -156,10 +161,7 @@ export function AdminShell({ children }: { children: React.ReactNode }) {
aria-haspopup="dialog"
/>
@@ -197,12 +199,7 @@ export function AdminShell({ children }: { children: React.ReactNode }) {
className="m-0 h-dvh max-h-none w-[min(20rem,85vw)] max-w-none bg-canvas p-0 text-ink backdrop:bg-black/50 open:flex open:flex-col"
>
-
-
-
- Admin
-
-
+
}
diff --git a/apps/admin/components/brand-logo.tsx b/apps/admin/components/brand-logo.tsx
new file mode 100644
index 0000000..9d112c1
--- /dev/null
+++ b/apps/admin/components/brand-logo.tsx
@@ -0,0 +1,31 @@
+import { cn } from '@tms/ui';
+import Image from 'next/image';
+
+export interface BrandLogoProps {
+ alt?: string;
+ className?: string;
+ priority?: boolean;
+ sizes?: string;
+}
+
+/** The canonical F.A.T.U brand mark, cropped and optimized from the supplied artwork. */
+export function BrandLogo({
+ alt = '',
+ className,
+ priority = false,
+ sizes = '40px',
+}: BrandLogoProps) {
+ return (
+
+
+
+ );
+}
diff --git a/apps/admin/public/brand/fatu-logo.png b/apps/admin/public/brand/fatu-logo.png
new file mode 100644
index 0000000..7a5ab51
Binary files /dev/null and b/apps/admin/public/brand/fatu-logo.png differ
diff --git a/apps/storefront/app/apple-icon.png b/apps/storefront/app/apple-icon.png
new file mode 100644
index 0000000..99a5824
Binary files /dev/null and b/apps/storefront/app/apple-icon.png differ
diff --git a/apps/storefront/app/icon.png b/apps/storefront/app/icon.png
new file mode 100644
index 0000000..ccbd3d8
Binary files /dev/null and b/apps/storefront/app/icon.png differ
diff --git a/apps/storefront/app/layout.tsx b/apps/storefront/app/layout.tsx
index de698b8..110f35d 100644
--- a/apps/storefront/app/layout.tsx
+++ b/apps/storefront/app/layout.tsx
@@ -25,6 +25,7 @@ const sans = IBM_Plex_Sans({
export const metadata: Metadata = {
metadataBase: new URL('https://fromafricatoyou.com'),
+ applicationName: 'F.A.T.U',
title: {
default: 'From Africa To You — Art-led apparel',
template: '%s · From Africa To You',
@@ -36,7 +37,26 @@ export const metadata: Metadata = {
siteName: 'From Africa To You',
title: 'From Africa To You — Art-led apparel',
description: 'A premium digital art gallery and interactive clothing-design experience.',
+ images: [
+ {
+ url: '/opengraph-image.png',
+ width: 1200,
+ height: 630,
+ alt: 'F.A.T.U — From Africa To You',
+ },
+ ],
},
+ twitter: {
+ card: 'summary_large_image',
+ title: 'From Africa To You — Art-led apparel',
+ description: 'A premium digital art gallery and interactive clothing-design experience.',
+ images: ['/opengraph-image.png'],
+ },
+ icons: {
+ icon: [{ url: '/icon.png', type: 'image/png', sizes: '512x512' }],
+ apple: [{ url: '/apple-icon.png', type: 'image/png', sizes: '180x180' }],
+ },
+ manifest: '/manifest.webmanifest',
robots: { index: true, follow: true },
};
diff --git a/apps/storefront/app/manifest.ts b/apps/storefront/app/manifest.ts
new file mode 100644
index 0000000..7ad3428
--- /dev/null
+++ b/apps/storefront/app/manifest.ts
@@ -0,0 +1,20 @@
+import type { MetadataRoute } from 'next';
+
+export default function manifest(): MetadataRoute.Manifest {
+ return {
+ name: 'From Africa To You',
+ short_name: 'F.A.T.U',
+ description: 'Original African artwork, made wearable.',
+ start_url: '/',
+ display: 'standalone',
+ background_color: '#fafaf7',
+ theme_color: '#fafaf7',
+ icons: [
+ {
+ src: '/icon.png',
+ sizes: '512x512',
+ type: 'image/png',
+ },
+ ],
+ };
+}
diff --git a/apps/storefront/app/opengraph-image.png b/apps/storefront/app/opengraph-image.png
new file mode 100644
index 0000000..2d9290a
Binary files /dev/null and b/apps/storefront/app/opengraph-image.png differ
diff --git a/apps/storefront/components/site/brand-logo.tsx b/apps/storefront/components/site/brand-logo.tsx
new file mode 100644
index 0000000..43c8335
--- /dev/null
+++ b/apps/storefront/components/site/brand-logo.tsx
@@ -0,0 +1,39 @@
+import { cn } from '@tms/ui';
+import Image from 'next/image';
+
+export interface BrandLogoProps {
+ alt?: string;
+ className?: string;
+ inverse?: boolean;
+ priority?: boolean;
+ sizes?: string;
+}
+
+/** The canonical F.A.T.U brand mark, cropped and optimized from the supplied artwork. */
+export function BrandLogo({
+ alt = '',
+ className,
+ inverse = false,
+ priority = false,
+ sizes = '48px',
+}: BrandLogoProps) {
+ return (
+
+
+
+ );
+}
diff --git a/apps/storefront/components/site/site-footer.tsx b/apps/storefront/components/site/site-footer.tsx
index 30861a3..ab7a856 100644
--- a/apps/storefront/components/site/site-footer.tsx
+++ b/apps/storefront/components/site/site-footer.tsx
@@ -1,6 +1,7 @@
import { Container } from '@tms/ui';
import { ArrowRight, Instagram, Twitter } from 'lucide-react';
import Link from 'next/link';
+import { BrandLogo } from '@/components/site/brand-logo';
import { footerNav } from '@/lib/nav';
/**
@@ -25,9 +26,12 @@ export function SiteFooter() {
{/* Mobile: brand full-width, then nav in a 2×2 grid. Desktop: brand + four columns. */}
-
- F.A.T.U
-
+
Hand-drawn art from across Africa, printed on cotton. From Africa, to you.
diff --git a/apps/storefront/components/site/site-header.tsx b/apps/storefront/components/site/site-header.tsx
index f026eca..d80add2 100644
--- a/apps/storefront/components/site/site-header.tsx
+++ b/apps/storefront/components/site/site-header.tsx
@@ -7,6 +7,7 @@ import { usePathname } from 'next/navigation';
import { type MouseEvent, useCallback, useEffect, useRef } from 'react';
import { useAuth } from '@/components/account/auth-provider';
import { useCart } from '@/components/cart/cart-provider';
+import { BrandLogo } from '@/components/site/brand-logo';
import { primaryNav } from '@/lib/nav';
/**
@@ -62,9 +63,10 @@ export function SiteHeader() {
- F.A.T.U
+
@@ -136,7 +138,10 @@ export function SiteHeader() {
className="tms-slideover m-0 ml-auto h-dvh max-h-none w-[min(22rem,85vw)] max-w-none bg-canvas p-0 text-ink open:flex open:flex-col"
>
-
Menu
+
+
+ Menu
+
}
diff --git a/apps/storefront/public/brand/fatu-logo.png b/apps/storefront/public/brand/fatu-logo.png
new file mode 100644
index 0000000..7a5ab51
Binary files /dev/null and b/apps/storefront/public/brand/fatu-logo.png differ
diff --git a/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-desktop-1280.png b/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-desktop-1280.png
index ed9c1c7..5c7d960 100644
Binary files a/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-desktop-1280.png and b/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-desktop-1280.png differ
diff --git a/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-desktop-1440.png b/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-desktop-1440.png
index 0a82835..242d863 100644
Binary files a/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-desktop-1440.png and b/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-desktop-1440.png differ
diff --git a/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-mobile-390.png b/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-mobile-390.png
index d6500ee..c2fd26b 100644
Binary files a/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-mobile-390.png and b/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-mobile-390.png differ
diff --git a/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-tablet-768.png b/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-tablet-768.png
index 6b6383d..ee89932 100644
Binary files a/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-tablet-768.png and b/apps/storefront/tests/__screenshots__/visual/showcase.spec.ts/home-tablet-768.png differ
diff --git a/apps/storefront/tests/visual/showcase.spec.ts b/apps/storefront/tests/visual/showcase.spec.ts
index 3931b6b..5f9296c 100644
--- a/apps/storefront/tests/visual/showcase.spec.ts
+++ b/apps/storefront/tests/visual/showcase.spec.ts
@@ -3,13 +3,36 @@ import { expect, test } from '@playwright/test';
test.describe('storefront foundation', () => {
test('homepage renders hero and gallery', async ({ page }) => {
await page.goto('/');
- await expect(page.getByRole('heading', { level: 1 })).toContainText('artwork is the hero');
- await expect(page.getByRole('heading', { name: 'From the gallery' })).toBeVisible();
+ await expect(page.getByRole('heading', { level: 1 })).toHaveText(/From Africa,\s*to you\./i);
+ await expect(page.getByRole('heading', { name: 'Shop by collection' })).toBeVisible();
// Skip link is the first focusable element.
await page.keyboard.press('Tab');
await expect(page.getByRole('link', { name: 'Skip to content' })).toBeFocused();
});
+ test('brand logo and install metadata are available', async ({ page, request }) => {
+ await page.goto('/');
+
+ const homeLink = page.getByRole('link', { name: 'F.A.T.U home' });
+ await expect(homeLink).toBeVisible();
+ await expect(homeLink.locator('img')).toHaveAttribute('src', /fatu-logo\.png/);
+ await expect(page.getByRole('img', { name: 'F.A.T.U — From Africa To You' })).toBeVisible();
+
+ const manifestResponse = await request.get('/manifest.webmanifest');
+ expect(manifestResponse.ok()).toBeTruthy();
+ await expect(manifestResponse.json()).resolves.toMatchObject({
+ name: 'From Africa To You',
+ short_name: 'F.A.T.U',
+ icons: [{ src: '/icon.png', sizes: '512x512', type: 'image/png' }],
+ });
+
+ for (const path of ['/icon.png', '/apple-icon.png', '/opengraph-image.png']) {
+ const response = await request.get(path);
+ expect(response.ok()).toBeTruthy();
+ expect(response.headers()['content-type']).toBe('image/png');
+ }
+ });
+
test('visual baseline — homepage', async ({ page }) => {
await page.goto('/');
await page.waitForLoadState('networkidle');
diff --git a/docs/handoffs/FRONTEND_HANDOFF.md b/docs/handoffs/FRONTEND_HANDOFF.md
index 6fb91ef..2f651f0 100644
--- a/docs/handoffs/FRONTEND_HANDOFF.md
+++ b/docs/handoffs/FRONTEND_HANDOFF.md
@@ -1,5 +1,26 @@
# Frontend Handoff
+## Canonical F.A.T.U logo system (TMS-F0-013, 2026-07-20) — VERIFIED
+
+The user-supplied transparent logo at `C:\Users\Admin\Downloads\FATU l design.png` is now the
+canonical visual mark. It was cropped to its true square artwork bounds before export; the supplied
+white-background variant is intentionally not used as a web source asset. Both apps receive their
+own optimized `/public/brand/fatu-logo.png`, `/app/icon.png`, and `/app/apple-icon.png` so they can
+deploy independently.
+
+Storefront coverage: sticky header, mobile menu, dark footer (with a warm light backing so black
+letterforms retain contrast), favicon/Apple icon, install manifest, and 1200×630 Open Graph/Twitter
+preview. Admin coverage: desktop sidebar, mobile header/drawer, sign-in screen, favicon, and Apple
+icon. `BrandLogo` components keep intrinsic dimensions, responsive `sizes`, empty alt text when a
+labelled link already supplies the accessible name, and descriptive alt text when the mark stands
+alone.
+
+Verification on `codex/fatu-logo-system` commit `af07bee`: storefront 289/289 tests, admin 125/125,
+both lint/typecheck/build green. Playwright inspected the rendered logo surfaces at 375px and 1440px;
+all asset/metadata endpoints return 200 and no console errors were emitted. Visual evidence and the
+focused design report live under
+`C:\Users\Admin\.gstack\projects\tai\designs\design-audit-20260720\`.
+
## Data source policy (F7, 2026-07-17) — DECIDED
**The question.** `DATA_SOURCE` was one all-or-nothing switch (`api` or `mock`) chosen when no
diff --git a/docs/progress/FRONTEND_TODO.md b/docs/progress/FRONTEND_TODO.md
index 1edb1e9..39917fb 100644
--- a/docs/progress/FRONTEND_TODO.md
+++ b/docs/progress/FRONTEND_TODO.md
@@ -7,6 +7,17 @@ lint, build, visual evidence, docs updated).
## Phase F0 — Reference audit & design foundation
+- [x] **TMS-F0-013** Canonical F.A.T.U logo system
+ - Status: **Verified** (2026-07-20)
+ - Evidence: the supplied transparent 6600×4928 master was tightly cropped and exported as an
+ optimized 1024px brand asset, 512px browser icon, 180px Apple icon, and 1200×630 social card.
+ Reusable logo components replace the storefront header/footer/mobile-menu wordmarks and the
+ admin desktop/mobile/login wordmarks. Storefront metadata now publishes branded Open Graph,
+ Twitter, icon, Apple-icon, and web-manifest entries. Responsive Playwright evidence covers
+ storefront header/footer/menu plus admin login/shell at 375px and 1440px. Storefront tests
+ 289/289, admin tests 125/125, both apps lint/typecheck/build green; asset and metadata routes
+ return 200 with no browser-console errors. Branch: `codex/fatu-logo-system`; commit `af07bee`.
+
- [x] **TMS-F0-001** Repository inspection & branch setup
- Status: Verified
- Evidence: main at `dd910ae9…` confirmed; branch `claude/f0-visual-foundation` from latest
diff --git a/package.json b/package.json
index 4ca94d4..a5078cc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "tai-manic-studios",
- "version": "0.1.0.0",
+ "version": "0.1.1.0",
"private": true,
"description": "Tai Manic Studios art-first commerce platform",
"license": "UNLICENSED",