Add brand kit, #/brand page, and responsive logo marks

Export script generates PNG/WebP/favicons/ZIP and OG image; nav uses symbol on mobile and horizontal lockup on desktop; press kit at #/brand with download links and print-friendly guidelines.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
defiQUG
2026-05-26 20:53:37 -07:00
co-authored by Cursor
parent 2019f56f27
commit 33aab0d3de
48 changed files with 569 additions and 77 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

+71
View File
@@ -0,0 +1,71 @@
{
"version": "1.0.0",
"organization": "Miracles in Motion Foundation",
"updated": "2026-05-27",
"colors": [
{ "name": "Forest green", "hex": "#1a3c34", "role": "primary background" },
{ "name": "Forest green (deep)", "hex": "#0f2922", "role": "dark text" },
{ "name": "Gold", "hex": "#c5a059", "role": "accent" },
{ "name": "Gold (bright)", "hex": "#d4af37", "role": "logo highlight" }
],
"typography": [
{ "name": "Playfair Display", "use": "Headings (web)", "source": "Self-hosted via site" },
{ "name": "Inter", "use": "Body and UI (web)", "source": "Self-hosted via site" }
],
"kits": [
{
"id": "full",
"title": "Complete brand kit (ZIP)",
"path": "/brand/MIM4U-Brand-Kit.zip",
"format": "ZIP",
"description": "All logos, favicons, and guidelines markdown"
}
],
"groups": [
{
"id": "symbol",
"title": "Symbol mark (icon only)",
"description": "Figure and starburst — mobile header, favicons, compact UI.",
"assets": [
{ "title": "Symbol (SVG, simplified vector)", "path": "/brand/logo-symbol.svg", "format": "SVG" },
{ "title": "Symbol 512px", "path": "/brand/logo-symbol-512.png", "format": "PNG" },
{ "title": "Symbol 256px", "path": "/brand/logo-symbol-256.png", "format": "PNG" },
{ "title": "Symbol 128px", "path": "/brand/logo-symbol-128.png", "format": "PNG" },
{ "title": "Symbol 64px", "path": "/brand/logo-symbol-64.png", "format": "PNG" }
]
},
{
"id": "horizontal",
"title": "Horizontal lockup",
"description": "Icon + MIRACLES IN MOTION FOUNDATION — desktop nav and footer.",
"assets": [
{ "title": "Horizontal (PNG)", "path": "/brand/logo-horizontal.png", "format": "PNG" },
{ "title": "Horizontal (WebP)", "path": "/brand/logo-horizontal.webp", "format": "WebP" },
{ "title": "Horizontal 2× width (PNG)", "path": "/brand/logo-horizontal-2x.png", "format": "PNG" }
]
},
{
"id": "square",
"title": "Square lockup",
"description": "Full stacked logo on green — social and print-friendly raster.",
"assets": [
{ "title": "Square (PNG)", "path": "/brand/logo-square.png", "format": "PNG" },
{ "title": "Square (WebP)", "path": "/brand/logo-square.webp", "format": "WebP" }
]
},
{
"id": "favicon",
"title": "Favicon & app icons",
"description": "Symbol on forest green background.",
"assets": [
{ "title": "favicon.ico", "path": "/brand/favicon.ico", "format": "ICO" },
{ "title": "16×16", "path": "/brand/favicon-16.png", "format": "PNG" },
{ "title": "32×32", "path": "/brand/favicon-32.png", "format": "PNG" },
{ "title": "180×180 (Apple touch)", "path": "/brand/favicon-180.png", "format": "PNG" },
{ "title": "192×192 (PWA)", "path": "/brand/favicon-192.png", "format": "PNG" },
{ "title": "512×512 (PWA)", "path": "/brand/favicon-512.png", "format": "PNG" },
{ "title": "Favicon (SVG)", "path": "/favicon.svg", "format": "SVG" }
]
}
]
}
+2
View File
@@ -6,6 +6,8 @@
"description": "Public website for Miracles In Motion 501(c)3 non-profit organization",
"scripts": {
"dev": "vite",
"brand:export": "bash scripts/brand/export-brand-assets.sh",
"prebuild": "npm run brand:export",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 15 KiB

+31
View File
@@ -0,0 +1,31 @@
# Miracles in Motion Foundation — Brand guidelines (summary)
## Colors
| Name | Hex | Use |
|------|-----|-----|
| Forest green | `#1a3c34` | Backgrounds, primary UI |
| Forest green (deep) | `#0f2922` | Text on light backgrounds |
| Gold | `#c5a059` | Accents, highlights |
| Gold (bright) | `#d4af37` | Logo mark, emphasis |
## Typography (web)
- **Headings:** Playfair Display (serif)
- **Body / UI:** Inter (sans-serif)
Logo type in lockups is part of the artwork; do not substitute fonts in the logo files.
## Logo usage
1. Use approved files from this kit only.
2. Do not stretch, rotate, or change logo colors.
3. Maintain clear space around the lockup (minimum: height of the “M” in MIRACLES).
4. **Nav / web header:** horizontal lockup (tablet/desktop) or symbol mark (mobile).
5. **Social / square placements:** square lockup with full name.
6. **Favicon / app icon:** symbol on forest green (`#1a3c34`).
7. Co-branding and sponsor logo placement require written approval — see [mim4u.org/#/legal](https://mim4u.org/#/legal).
## Contact
Brand questions: contact@mim4u.org
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

+37
View File
@@ -0,0 +1,37 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 99" fill="none" role="img" aria-label="Miracles in Motion Foundation symbol">
<title>Miracles in Motion Foundation</title>
<!-- Simplified vector mark (transparent). High-fidelity artwork: logo-symbol-512.png -->
<circle cx="17.5" cy="16.5" r="5.2" fill="#d4af37"/>
<path
d="M14 82c3.5-14 8-22 10-38 2.5 10 6 18 10 38"
stroke="#c5a059"
stroke-width="4.2"
stroke-linecap="round"
stroke-linejoin="round"
fill="none"
/>
<path
d="M22 38 L28 28 L34 38"
stroke="#d4af37"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
fill="none"
/>
<path
d="M38 26 L48 14 L58 22 L68 12 L78 20"
stroke="#c5a059"
stroke-width="2.8"
stroke-linecap="round"
fill="none"
/>
<g stroke="#d4af37" stroke-width="2.2" stroke-linecap="round">
<line x1="72" y1="14" x2="72" y2="8"/>
<line x1="78" y1="16" x2="84" y2="12"/>
<line x1="80" y1="22" x2="88" y2="22"/>
<line x1="66" y1="16" x2="60" y2="12"/>
<line x1="64" y1="22" x2="56" y2="22"/>
<line x1="74" y1="10" x2="76" y2="4"/>
<line x1="68" y1="8" x2="66" y2="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 B

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

+11 -12
View File
@@ -1,14 +1,13 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Miracles in Motion Foundation">
<rect width="32" height="32" rx="6" fill="#1a3c34"/>
<!-- Stylized figure + starburst (brand mark simplification) -->
<circle cx="16" cy="7.5" r="2.2" fill="#d4af37"/>
<path d="M11 22c2-5 4.5-7.5 5-12 1.2 4 3.2 6.5 5 12" stroke="#c5a059" stroke-width="1.8" stroke-linecap="round" fill="none"/>
<path d="M13.5 11.5l2.5-3 2.5 3" stroke="#d4af37" stroke-width="1.2" stroke-linecap="round" fill="none"/>
<g stroke="#d4af37" stroke-width="0.7" stroke-linecap="round">
<line x1="20" y1="6" x2="20" y2="3.5"/>
<line x1="22.5" y1="7" x2="24.5" y2="5.5"/>
<line x1="23.5" y1="9.5" x2="26" y2="9.5"/>
<line x1="17.5" y1="7" x2="15.5" y2="5.5"/>
<line x1="16.5" y1="9.5" x2="14" y2="9.5"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 99" fill="none" role="img" aria-label="Miracles in Motion Foundation">
<rect width="100" height="99" rx="12" fill="#1a3c34"/>
<circle cx="17.5" cy="16.5" r="5.2" fill="#d4af37"/>
<path d="M14 82c3.5-14 8-22 10-38 2.5 10 6 18 10 38" stroke="#c5a059" stroke-width="4.2" stroke-linecap="round" fill="none"/>
<path d="M22 38 L28 28 L34 38" stroke="#d4af37" stroke-width="3" stroke-linecap="round" fill="none"/>
<g stroke="#d4af37" stroke-width="2.2" stroke-linecap="round">
<line x1="72" y1="14" x2="72" y2="8"/>
<line x1="78" y1="16" x2="84" y2="12"/>
<line x1="80" y1="22" x2="88" y2="22"/>
<line x1="66" y1="16" x2="60" y2="12"/>
<line x1="64" y1="22" x2="56" y2="22"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 566 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 KiB

+5
View File
@@ -35,4 +35,9 @@
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mim4u.org/#/brand</loc>
<changefreq>monthly</changefreq>
<priority>0.6</priority>
</url>
</urlset>
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env bash
# Generate web-ready brand assets and MIM4U-Brand-Kit.zip from sources in assets/brand-sources/.
# Requires: ImageMagick (convert). Run from repo root: ./scripts/brand/export-brand-assets.sh
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MIM_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
SRC="$MIM_ROOT/assets/brand-sources"
OUT="$MIM_ROOT/public/brand"
PUBLIC="$MIM_ROOT/public"
GREEN="#1a3c34"
if ! command -v convert >/dev/null 2>&1; then
echo "Error: ImageMagick convert is required." >&2
exit 1
fi
mkdir -p "$OUT"
symbol="$SRC/logo-symbol-source.png"
horizontal="$SRC/logo-horizontal-source.png"
square="$SRC/logo-square-source.png"
for f in "$symbol" "$horizontal" "$square"; do
if [[ ! -f "$f" ]]; then
echo "Missing source: $f" >&2
exit 1
fi
done
echo "Exporting symbol PNG sizes..."
for size in 64 128 256 512 1024; do
convert "$symbol" -resize "${size}x${size}" -strip "$OUT/logo-symbol-${size}.png"
done
cp "$OUT/logo-symbol-512.png" "$OUT/logo-symbol.png"
echo "Exporting horizontal PNG/WebP..."
convert "$horizontal" -strip "$OUT/logo-horizontal.png"
convert "$horizontal" -quality 88 -define webp:method=6 "$OUT/logo-horizontal.webp"
convert "$horizontal" -resize 2048x -strip "$OUT/logo-horizontal-2x.png"
echo "Exporting square PNG/WebP..."
convert "$square" -strip "$OUT/logo-square.png"
convert "$square" -quality 88 -define webp:method=6 "$OUT/logo-square.webp"
echo "Exporting favicon / touch icons (symbol on brand green)..."
for size in 16 32 180 192 512; do
convert "$symbol" -background "$GREEN" -gravity center -resize "${size}x${size}" -extent "${size}x${size}" -strip "$OUT/favicon-${size}.png"
done
# Multi-size favicon.ico
convert "$OUT/favicon-16.png" "$OUT/favicon-32.png" "$OUT/favicon.ico"
# Root copies for site + PWA
cp "$OUT/logo-horizontal.png" "$PUBLIC/logo-horizontal.png"
cp "$OUT/logo-square.png" "$PUBLIC/logo.png"
cp "$OUT/logo-symbol.png" "$PUBLIC/logo-symbol.png"
cp "$OUT/favicon-16.png" "$PUBLIC/favicon-16x16.png"
cp "$OUT/favicon-32.png" "$PUBLIC/favicon-32x32.png"
cp "$OUT/favicon-180.png" "$PUBLIC/apple-touch-icon.png"
cp "$OUT/favicon-192.png" "$PUBLIC/favicon-192x192.png"
cp "$OUT/favicon-512.png" "$PUBLIC/favicon-512x512.png"
cp "$OUT/favicon.ico" "$PUBLIC/favicon.ico"
echo "Generating OG social image (1200×630)..."
convert "$horizontal" -resize 1200x630^ -gravity center -extent 1200x630 -strip "$OUT/og-image.png"
cp "$OUT/og-image.png" "$PUBLIC/og-image.png" 2>/dev/null || cp "$OUT/og-image.png" "$PUBLIC/og-image.jpg" 2>/dev/null || true
if [[ -f "$PUBLIC/og-image.jpg" ]]; then
convert "$OUT/og-image.png" -quality 90 "$PUBLIC/og-image.jpg"
fi
echo "Building brand kit ZIP..."
(
cd "$OUT"
rm -f MIM4U-Brand-Kit.zip
zip -q MIM4U-Brand-Kit.zip \
logo-symbol.svg \
logo-symbol.png logo-symbol-64.png logo-symbol-128.png logo-symbol-256.png logo-symbol-512.png logo-symbol-1024.png \
logo-horizontal.png logo-horizontal.webp logo-horizontal-2x.png \
logo-square.png logo-square.webp \
favicon.ico favicon-16.png favicon-32.png favicon-180.png favicon-192.png favicon-512.png \
og-image.png \
BRAND_GUIDELINES.md 2>/dev/null || true
)
echo "Done. Outputs: $OUT"
+29 -26
View File
@@ -58,14 +58,15 @@ import {
import AIAssistancePortal from './components/AIAssistancePortal'
// Phase 3B: Enterprise Components
import AdvancedAnalyticsDashboard from './components/AdvancedAnalyticsDashboard'
import MobileVolunteerApp from './components/MobileVolunteerApp'
import StaffTrainingDashboard from './components/StaffTrainingDashboard'
import MimChatAgent from './components/MimChatAgent'
import AdvancedAnalyticsDashboard from './components/AdvancedAnalyticsDashboard'
import MobileVolunteerApp from './components/MobileVolunteerApp'
import StaffTrainingDashboard from './components/StaffTrainingDashboard'
import MimChatAgent from './components/MimChatAgent'
// Phase 4: Extracted Components
import { Navigation } from './components/Navigation'
import { Footer } from './components/Footer'
import { BrandAssetsPage } from './pages/BrandPage'
/**
* Miracles in Motion — Complete Non-Profit Website
@@ -2184,7 +2185,7 @@ function SponsorsPage() {
]
return (
<PageShell title="Corporate Sponsorship" icon={Building2} eyebrow="Partner with purpose" cta={<a className="btn-secondary" href="#">Download prospectus</a>}>
<PageShell title="Corporate Sponsorship" icon={Building2} eyebrow="Partner with purpose" cta={<a className="btn-secondary" href="#/brand">Brand assets</a>}>
<div className="grid gap-6 md:grid-cols-2">
<div className="space-y-6">
{tiers.map((t) => (
@@ -2368,7 +2369,7 @@ function LegalPage() {
</PolicySection>
<PolicySection id="sponsorship-terms" title="Sponsorship Terms & Logo Use">
<ul className="list-disc pl-5 space-y-2">
<li>Logo usage requires prior written approval and must follow brand guidelines.</li>
<li>Logo usage requires prior written approval and must follow our <a className="underline" href="#/brand">brand assets and guidelines</a>.</li>
<li>Sponsorship does not imply endorsement of products or services.</li>
<li>Benefits may be adjusted for equivalency based on availability.</li>
</ul>
@@ -4576,6 +4577,8 @@ function AppContent() {
return <TestimoniesPage />
case '/legal':
return <LegalPage />
case '/brand':
return <BrandAssetsPage />
case '/impact':
return <ImpactReportPage />
case '/request-assistance':
@@ -4603,9 +4606,9 @@ function AppContent() {
}
}
return (
<div className={`min-h-screen transition-colors duration-300 bg-neutral-50 text-neutral-900 antialiased selection:bg-primary-200/60 dark:bg-neutral-950 dark:text-neutral-50 ${darkMode ? 'dark' : ''}`}>
<BackgroundDecor />
return (
<div className={`min-h-screen transition-colors duration-300 bg-neutral-50 text-neutral-900 antialiased selection:bg-primary-200/60 dark:bg-neutral-950 dark:text-neutral-50 ${darkMode ? 'dark' : ''}`}>
<BackgroundDecor />
<SkipToContent />
{/* Offline Indicator */}
@@ -4628,20 +4631,20 @@ function AppContent() {
<main id="content" className="relative flex-1">
{renderPage()}
</main>
<Footer />
{![
'/admin-portal',
'/volunteer-portal',
'/resource-portal',
'/analytics',
'/ai-portal',
'/advanced-analytics',
'/mobile-volunteer',
'/staff-training'
].includes(currentPath) && <MimChatAgent currentPath={currentPath} />}
<StickyDonate />
<CookieBanner />
</div>
)
}
<Footer />
{![
'/admin-portal',
'/volunteer-portal',
'/resource-portal',
'/analytics',
'/ai-portal',
'/advanced-analytics',
'/mobile-volunteer',
'/staff-training'
].includes(currentPath) && <MimChatAgent currentPath={currentPath} />}
<StickyDonate />
<CookieBanner />
</div>
)
}
+1
View File
@@ -43,6 +43,7 @@ export function Footer() {
<h3 className="font-semibold">Organization</h3>
<ul className="mt-4 space-y-2 text-sm">
<li><a href="#/testimonies" className="navlink">Testimonials</a></li>
<li><a href="#/brand" className="navlink">Brand assets</a></li>
<li><a href="#/legal" className="navlink">Legal & Policies</a></li>
<li><a href="mailto:[email protected]" className="navlink">Contact Us</a></li>
<li><a href="tel:+18184916884" className="navlink">(818) 491-6884</a></li>
+2 -2
View File
@@ -17,7 +17,7 @@ interface SEOHeadProps {
export function SEOHead({
title = 'Miracles in Motion - Empowering Students with Essential Support',
description = 'A 501(c)(3) nonprofit providing students with school supplies, clothing, and emergency support to help them succeed in school and life.',
image = '/og-image.jpg',
image = '/og-image.png',
url = 'https://mim4u.org',
type = 'website',
article
@@ -87,7 +87,7 @@ export function SEOHead({
"@type": "Organization",
"name": "Miracles in Motion",
"url": "https://mim4u.org",
"logo": "https://mim4u.org/logo.png",
"logo": "https://mim4u.org/brand/logo-horizontal.png",
"description": description,
"foundingDate": "2020",
"areaServed": "United States",
+55 -5
View File
@@ -1,29 +1,79 @@
export type LogoMarkVariant = 'nav' | 'footer' | 'square'
export interface LogoMarkProps {
/** nav/footer: full wordmark; square: compact icon tile */
/** nav: symbol on mobile, horizontal on md+; footer: horizontal; square: stacked lockup */
variant?: LogoMarkVariant
className?: string
}
const LOGO_SRC = '/logo.png'
const BRAND = {
symbolSvg: '/brand/logo-symbol.svg',
symbolPng: '/brand/logo-symbol-512.png',
horizontal: '/brand/logo-horizontal.png',
square: '/brand/logo-square.png',
} as const
export function LogoMark({ variant = 'nav', className = '' }: LogoMarkProps) {
const isDecorative = variant === 'nav' || variant === 'footer'
if (variant === 'nav') {
return (
<span
className={['logo-mark', 'logo-mark--nav', className].filter(Boolean).join(' ')}
aria-hidden={true}
>
<img
src={BRAND.symbolSvg}
alt=""
className="logo-mark__img logo-mark__img--symbol md:hidden"
width={100}
height={99}
decoding="async"
fetchPriority="high"
/>
<img
src={BRAND.horizontal}
alt=""
className="logo-mark__img logo-mark__img--horizontal hidden md:block"
width={1024}
height={354}
decoding="async"
fetchPriority="high"
/>
</span>
)
}
if (variant === 'footer') {
return (
<span
className={['logo-mark', 'logo-mark--footer', className].filter(Boolean).join(' ')}
aria-hidden={true}
>
<img
src={BRAND.horizontal}
alt=""
className="logo-mark__img logo-mark__img--horizontal"
width={1024}
height={354}
decoding="async"
/>
</span>
)
}
return (
<span
className={['logo-mark', `logo-mark--${variant}`, className].filter(Boolean).join(' ')}
className={['logo-mark', 'logo-mark--square', className].filter(Boolean).join(' ')}
aria-hidden={isDecorative || undefined}
>
<img
src={LOGO_SRC}
src={BRAND.square}
alt={isDecorative ? '' : 'Miracles in Motion Foundation'}
className="logo-mark__img"
width={1024}
height={1024}
decoding="async"
fetchPriority={variant === 'nav' ? 'high' : undefined}
/>
</span>
)
+35 -23
View File
@@ -71,7 +71,7 @@
}
@layer components {
/* Official logo (public/logo.png) */
/* Brand logos: /brand/logo-symbol.svg, logo-horizontal.png, logo-square.png */
.logo-mark {
display: inline-flex;
align-items: center;
@@ -83,72 +83,75 @@
.logo-mark__img {
display: block;
object-fit: contain;
object-position: left center;
}
/* Mobile-first; scale up on tablet/desktop (square asset: height drives width) */
/* Nav: symbol (square) on mobile, horizontal lockup on md+ */
.logo-mark--nav {
height: 2.25rem;
height: 2.5rem;
}
.logo-mark--nav .logo-mark__img {
.logo-mark--nav .logo-mark__img--symbol {
height: 100%;
width: auto;
max-width: 9rem;
object-position: center;
max-width: 2.75rem;
}
@media (min-width: 640px) {
@media (min-width: 768px) {
.logo-mark--nav {
height: 3rem;
height: 3.25rem;
}
.logo-mark--nav .logo-mark__img {
max-width: 11rem;
.logo-mark--nav .logo-mark__img--horizontal {
height: 100%;
width: auto;
max-width: min(14rem, 42vw);
}
}
@media (min-width: 1024px) {
.logo-mark--nav {
height: 4rem;
height: 3.5rem;
}
.logo-mark--nav .logo-mark__img {
max-width: 14rem;
.logo-mark--nav .logo-mark__img--horizontal {
max-width: 15rem;
}
}
@media (min-width: 1280px) {
.logo-mark--nav {
height: 4.25rem;
height: 3.75rem;
}
.logo-mark--nav .logo-mark__img {
max-width: 15.5rem;
.logo-mark--nav .logo-mark__img--horizontal {
max-width: 16.5rem;
}
}
/* Footer: always horizontal */
.logo-mark--footer {
height: 2.75rem;
}
.logo-mark--footer .logo-mark__img {
.logo-mark--footer .logo-mark__img--horizontal {
height: 100%;
width: auto;
max-width: 10rem;
max-width: min(12rem, 80vw);
}
@media (min-width: 640px) {
.logo-mark--footer {
height: 3.25rem;
}
.logo-mark--footer .logo-mark__img {
max-width: 12rem;
.logo-mark--footer .logo-mark__img--horizontal {
max-width: 14rem;
}
}
@media (min-width: 1024px) {
.logo-mark--footer {
height: 3.75rem;
height: 3.5rem;
}
.logo-mark--footer .logo-mark__img {
max-width: 14rem;
.logo-mark--footer .logo-mark__img--horizontal {
max-width: 16rem;
}
}
@@ -569,6 +572,15 @@
}
@media print {
.no-print,
header,
footer,
.sticky-donate,
[class*="MimChat"],
dialog {
display: none !important;
}
.no-print {
display: none !important;
}
+184
View File
@@ -0,0 +1,184 @@
import { Download, Palette, Printer, Type } from 'lucide-react'
import manifest from '../../../config/brand-assets.manifest.json'
type BrandManifest = typeof manifest
export function BrandAssetsPage() {
const data = manifest as BrandManifest
return (
<div className="mx-auto max-w-4xl px-4 py-12 sm:px-6 lg:px-8">
<div className="section-header mb-10">
<div className="section-eyebrow">Press & partners</div>
<h1 className="section-title">Brand assets</h1>
<p className="section-subtitle">
Official logos, colors, and favicons for Miracles in Motion Foundation. Use only these
files; do not recreate or recolor the mark.
</p>
</div>
<div className="mb-8 flex flex-wrap gap-3 print:hidden">
<a href="/brand/MIM4U-Brand-Kit.zip" className="btn-primary" download>
<Download className="h-4 w-4" aria-hidden />
Download complete kit (ZIP)
</a>
<button
type="button"
className="btn-secondary"
onClick={() => window.print()}
>
<Printer className="h-4 w-4" aria-hidden />
Print guidelines
</button>
</div>
<section className="card mb-8" id="usage">
<h2 className="font-semibold tracking-tight">Usage (summary)</h2>
<ul className="mt-3 list-disc space-y-2 pl-5 text-sm text-neutral-700 dark:text-neutral-300">
<li>Do not stretch, rotate, or change logo colors.</li>
<li>
Keep clear space around the lockup (at least the height of the capital M in MIRACLES).
</li>
<li>
<strong>Website header:</strong> horizontal lockup on tablet/desktop; symbol mark on
mobile.
</li>
<li>
<strong>Favicon / app icon:</strong> symbol on forest green (<code>#1a3c34</code>).
</li>
<li>
Sponsor and co-branding use requires approval — see{' '}
<a className="underline text-primary-600 dark:text-secondary-400" href="#/legal#sponsorship-terms">
Sponsorship Terms
</a>
.
</li>
<li>
Questions:{' '}
<a className="underline" href="mailto:[email protected]">
contact@mim4u.org
</a>
</li>
</ul>
</section>
<section className="card mb-8">
<div className="flex items-center gap-2">
<Palette className="h-5 w-5 text-primary-600 dark:text-secondary-400" aria-hidden />
<h2 className="font-semibold tracking-tight">Colors</h2>
</div>
<div className="mt-4 grid gap-3 sm:grid-cols-2">
{data.colors.map((c) => (
<div
key={c.hex}
className="flex items-center gap-3 rounded-xl border border-neutral-200/80 p-3 dark:border-white/10"
>
<span
className="h-12 w-12 shrink-0 rounded-lg border border-black/10 shadow-inner"
style={{ backgroundColor: c.hex }}
aria-hidden
/>
<div className="text-sm">
<div className="font-medium">{c.name}</div>
<div className="font-mono text-xs text-neutral-600 dark:text-neutral-400">{c.hex}</div>
<div className="text-xs text-neutral-500">{c.role}</div>
</div>
</div>
))}
</div>
</section>
<section className="card mb-8">
<div className="flex items-center gap-2">
<Type className="h-5 w-5 text-primary-600 dark:text-secondary-400" aria-hidden />
<h2 className="font-semibold tracking-tight">Typography (website)</h2>
</div>
<ul className="mt-3 space-y-2 text-sm text-neutral-700 dark:text-neutral-300">
{data.typography.map((t) => (
<li key={t.name}>
<strong>{t.name}</strong> — {t.use}
</li>
))}
</ul>
<p className="mt-3 text-xs text-neutral-500 dark:text-neutral-400">
Type in the logo artwork is part of the supplied files; do not set live text in a substitute
font to imitate the lockup.
</p>
</section>
{data.groups.map((group) => (
<section key={group.id} className="card mb-6" id={`assets-${group.id}`}>
<h2 className="font-semibold tracking-tight">{group.title}</h2>
<p className="mt-1 text-sm text-neutral-600 dark:text-neutral-400">{group.description}</p>
<div className="mt-4 overflow-x-auto">
<table className="w-full text-left text-sm">
<thead>
<tr className="border-b border-neutral-200 dark:border-white/10">
<th className="py-2 pr-4 font-medium">File</th>
<th className="py-2 pr-4 font-medium">Format</th>
<th className="py-2 font-medium">Download</th>
</tr>
</thead>
<tbody>
{group.assets.map((asset) => (
<tr
key={asset.path}
className="border-b border-neutral-100 dark:border-white/5"
>
<td className="py-3 pr-4">{asset.title}</td>
<td className="py-3 pr-4 font-mono text-xs">{asset.format}</td>
<td className="py-3">
<a
href={asset.path}
className="inline-flex items-center gap-1 text-primary-600 hover:underline dark:text-secondary-400"
download
>
<Download className="h-3.5 w-3.5" aria-hidden />
{asset.path.split('/').pop()}
</a>
</td>
</tr>
))}
</tbody>
</table>
</div>
{group.id === 'horizontal' && (
<div className="mt-4 rounded-xl bg-primary-600/10 p-4 dark:bg-primary-900/20">
<img
src="/brand/logo-horizontal.png"
alt=""
className="mx-auto h-16 w-auto max-w-full object-contain md:h-20"
width={1024}
height={354}
/>
</div>
)}
{group.id === 'symbol' && (
<div className="mt-4 flex flex-wrap items-center justify-center gap-6 rounded-xl bg-neutral-100 p-6 dark:bg-neutral-900">
<img
src="/brand/logo-symbol.svg"
alt=""
className="h-20 w-20 object-contain"
width={100}
height={99}
/>
<img
src="/brand/logo-symbol-512.png"
alt=""
className="h-20 w-20 object-contain"
width={512}
height={512}
/>
</div>
)}
</section>
))}
<p className="text-center text-xs text-neutral-500 print:mt-8">
© Miracles in Motion Foundation. Kit version {data.version} · Updated {data.updated}
</p>
</div>
)
}
export default BrandAssetsPage
+1
View File
@@ -0,0 +1 @@
export { BrandAssetsPage, default } from './BrandAssetsPage'
+1 -1
View File
@@ -26,6 +26,6 @@
"@/*": ["./src/*"]
}
},
"include": ["src"],
"include": ["src", "config/brand-assets.manifest.json"],
"references": [{ "path": "./tsconfig.node.json" }]
}
+17 -8
View File
@@ -9,7 +9,16 @@ export default defineConfig({
react(),
VitePWA({
registerType: 'prompt',
includeAssets: ['favicon.svg', 'logo.png', 'robots.txt', 'site.webmanifest'],
includeAssets: [
'favicon.svg',
'favicon.ico',
'logo.png',
'logo-horizontal.png',
'logo-symbol.png',
'robots.txt',
'site.webmanifest',
'brand/**/*',
],
manifest: {
name: 'Miracles in Motion Foundation',
short_name: 'MiM',
@@ -24,21 +33,21 @@ export default defineConfig({
src: '/favicon.svg',
sizes: 'any',
type: 'image/svg+xml',
purpose: 'any'
purpose: 'any',
},
{
src: '/favicon-192x192.png',
src: '/brand/favicon-192.png',
sizes: '192x192',
type: 'image/png',
purpose: 'any maskable'
purpose: 'any maskable',
},
{
src: '/favicon-512x512.png',
src: '/brand/favicon-512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable'
}
]
purpose: 'any maskable',
},
],
},
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg,webp}'],