alumni_lookup

Champion Portal — Design Guidelines

Canonical sources: Portal philosophy, posture, and language live in /docs/planning/champion-portal/source/README.md.
Use these sources (including CHRIST_CENTERED__IDENTITY_STATEMENT.md) when writing specs or user-facing copy. Prefer quoting/paraphrasing over inventing new language.

Version: 2.3
Last Updated: 2026-01-10
Purpose: Ensure the Champion Portal feels warm, welcoming, and distinctly Belmont
Status: Living Document — Use this prominently for all visual refresh work


Table of Contents

  1. Design Philosophy
  2. Visual Refresh Principles
  3. Brand Foundations
  4. Layout & Density
  5. UI Components
  6. Dashboard Patterns
  7. Recognition & Celebration
  8. Mobile-First Polish
  9. Accessibility
  10. Implementation Notes
  11. Image Request Checklist

1. Design Philosophy

Warm, Not Sterile

The Champion Portal is a community, not a corporate portal. Every design decision should reinforce that Champions are welcomed, valued, and connected.

❌ Avoid:

✅ Embrace:

Community Over Utility

This isn’t just a tool—it’s a place to belong. Design should:

Belmont-Aligned, Not Belmont-Wallpapered

Use Belmont elements as structure, not decoration:

The goal: Feel like a Belmont product without looking like a marketing brochure.

Recognition Matters

Per JOBS-TO-BE-DONE.md Job C10:

“When I put effort into being a Champion, I want to see that my contributions matter.”

Every feature should ask: How can we recognize the people who contribute?


2. Visual Refresh Principles

These are non-negotiables for all new design work:

# Principle What It Means
1 Warmth over sterility Friendly colors, soft shadows, rounded corners, human language
2 Scannable layout Clear visual hierarchy, obvious sections, breathing room
3 Visual differentiation Each section has distinct character (icon, accent, tint)
4 Mobile-first polish Touch-friendly, thumb-zone aware, responsive by default
5 Belmont identity with restraint Brand colors anchor, but don’t overwhelm

The “Is It Too Sterile?” Checklist

If a page feels cold or corporate, fix it in this order:

  1. Whitespace and grouping — Add breathing room, reduce clutter
  2. Surface tint and shadows — Warm backgrounds, soft depth
  3. Typography size/line-height — Bigger, more comfortable text
  4. Icons and section accents — Visual landmarks to scan
  5. Only then consider adding more color

3. Brand Foundations

3.1 Colors (Belmont-first, App-friendly)

Use the Belmont digital palette for the portal UI (it’s explicitly intended for screens with better contrast).

Primary Colors

Color Digital Hex Tailwind Class Usage
Belmont Blue #001D54 bg-belmontblue, text-belmontblue Primary anchor — headers, nav, buttons, selected states, focus rings
Belmont Red #B21029 bg-belmontred, text-belmontred Secondary emphasis — alerts, badges, destructive actions, rare highlights

⚠️ Belmont Blue is the primary anchor color and should be the dominant brand signal.
Belmont Red is secondary and should show up as emphasis, not wallpaper.

The “Tasteful Belmont” Rule

💡 If the UI starts to feel “too blue,” fix it with warm neutrals and spacing — not by swapping Belmont Blue out.

Secondary/Supporting Colors

Color Hex Tailwind Class Usage
Admissions Blue #1D4289 bg-admissionsblue Alternative primary for variety
Fountain Blue #2874AF bg-fountainblue Secondary buttons, hover states
Sky Blue #6AB3E7 bg-skyblue Highlights, links, engagement indicators

Warm Neutrals (Anti-Sterile Foundation)

Use warm-leaning neutrals for surfaces so the portal feels hospitable:

Purpose Recommendation
Page backgrounds Off-white / warm gray (avoid pure white everywhere)
Borders Soft, low-contrast (not harsh lines)
Cards Tinted surfaces or soft white with subtle shadow
Text Dark gray (#3D3D3D), not pure black

Avoid:

Section Accents (Controlled Differentiation)

Assign each major area a single accent that shows up as:

Keep accents subtle so Belmont Blue remains “home base.”

Example Color Applications

<!-- Primary button (Belmont Blue) -->
<button class="bg-belmontblue hover:bg-fountainblue text-white px-4 py-2 rounded-lg">
  Say Hello
</button>

<!-- Secondary button -->
<button class="bg-white border border-belmontblue text-belmontblue hover:bg-gray-50 px-4 py-2 rounded-lg">
  Learn More
</button>

<!-- Destructive action (Belmont Red, sparingly) -->
<button class="bg-belmontred hover:bg-red-800 text-white px-4 py-2 rounded-lg">
  Delete Account
</button>

<!-- Card with warmth -->
<div class="bg-white border border-gray-200 rounded-xl p-6 shadow-sm hover:shadow-md transition">
  <!-- Content -->
</div>

3.2 Typography (Belmont-aligned, Readable UI)

Font Families

Belmont’s primary web typefaces:

If licenses unavailable, Belmont approves these substitutes:

Currently configured in application.tailwind.css:

Purpose Font Tailwind Class
Body text Inter font-sans (default)
Headings Montserrat font-sansalt

UI Typography Rules (Warmth + Clarity)

Rule Why
Bigger default body text Avoid tiny “admin UI” sizing — aim for 16px+
Softer hierarchy Fewer ALL CAPS labels, fewer ultra-bold headings
Comfortable line-height For paragraph copy, empty states, instructions
Use serif sparingly For quotes, “story” moments, short callouts — not dense UI text

Typography Examples

<!-- Page titles -->
<h1 class="font-sansalt text-3xl font-bold text-belmontblue">
  Welcome, Sarah
</h1>

<!-- Section headers -->
<h2 class="font-sansalt text-xl font-semibold text-gray-800">
  Champions in Nashville
</h2>

<!-- Body text (comfortable) -->
<p class="text-base text-gray-700 leading-relaxed">
  Connect with fellow Bruins in your city.
</p>

<!-- Helper text -->
<p class="text-sm text-gray-500 leading-relaxed">
  This helps other Champions find you.
</p>

Tone of Voice


3.3 Iconography

Icon Style

Use a single icon set across the portal (consistent stroke, corner radius, visual weight).

Recommended: Heroicons — outline style

Context Icon Usage
Contact/Message envelope Contact button, messaging
Profile user-circle Profile views, account
Directory users Champion directory
Events calendar Event listings
Location map-pin City/location indicators
Search magnifying-glass Directory search
Success check-circle Confirmations
Activity sparkles Recent activity, engagement
Settings cog-6-tooth Account settings
Help question-mark-circle FAQ, help pages

Icon Principles

Icon Examples

<!-- Icon with text (button) -->
<button class="inline-flex items-center gap-2 bg-belmontblue text-white px-4 py-2 rounded-lg">
  <%= heroicon "envelope", variant: :outline, options: { class: "w-5 h-5" } %>
  Say Hello
</button>

<!-- Icon-only (with accessibility) -->
<button aria-label="View profile" class="p-2 hover:bg-gray-100 rounded-lg">
  <%= heroicon "user-circle", variant: :outline, options: { class: "w-6 h-6 text-belmontblue" } %>
</button>

Avoid:

Champion Role Icons & Seals

The four Champion roles (Community Builder, Digital Ambassador, Connection Advisor, Giving Advocate) each have two visual assets in /public/:

Asset Files Format Use Case
Icons {role}-icon.svg Hexagonal badge, no text, currentColor Inline next to supporting text
Seals {role}-seal.svg Circular badge with role name & virtues baked in Standalone/hero contexts

Helpers (in ApplicationHelper):

When to use which:

Context Asset Why
Next to role name/title (cards, lists, nav, radio buttons) Icon Text provides context; icon is a visual accent
Hero/celebration header (standalone, no adjacent text) Seal Seal includes the role name and virtues; self-explanatory
Email templates Emoji Inline SVG is unreliable in email clients; keep emoji fallback

Sizing rules:

Role color mapping: | Role | Color Class | |——|————-| | Community Builder | text-belmontblue | | Digital Ambassador | text-skyblue | | Connection Advisor | text-fountainblue | | Giving Advocate | text-belmontred |


4. Layout & Density

4.1 Scannable, Not Sparse

Sterile UIs often fail because everything is evenly tight. Instead:

Pattern Why
Generous vertical spacing between sections Creates clear visual breaks
Tight spacing within components Forms, tables stay scannable
2–3 content zones per page Not 7–10 little boxes

4.2 Belmont Homepage Cues (Translated for Apps)

Belmont’s homepage leans on:

In the portal, translate that into:

4.3 Warmth Mechanics (Physics, Not Just Color)

Element Warm Approach
Cards Noticeably rounded corners (not barely rounded)
Shadows Soft, subtle shadows with low opacity
Dividers Lighter borders, fewer hard lines
Backgrounds Tinted surfaces instead of stark white

4.4 Page Structure Template

┌─────────────────────────────────────────────────────────────────────┐
│ [PAGE HEADER]                                                       │
│ Title + 1–2 line description + optional action button               │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│ [SECTION 1] ──────────────────────────────────────────────          │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐            │
│ │     Card       │ │     Card       │ │     Card       │            │
│ └────────────────┘ └────────────────┘ └────────────────┘            │
│                                                                     │
│ [SECTION 2] ──────────────────────────────────────────────          │
│ ┌───────────────────────────────────────────────────────┐           │
│ │ Larger content block or list                          │           │
│ └───────────────────────────────────────────────────────┘           │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

5. UI Components

5.1 Cards

Cards should feel like “inviting surfaces,” not “dashboard tiles.”

Card anatomy:

<!-- Standard card -->
<div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm hover:shadow-md transition">
  <div class="flex items-start gap-3">
    <%= heroicon "users", variant: :outline, options: { class: "w-6 h-6 text-belmontblue flex-shrink-0" } %>
    <div>
      <h3 class="font-semibold text-gray-900">Champions Near You</h3>
      <p class="text-sm text-gray-600 mt-1">Connect with 23 Champions in Nashville</p>
    </div>
  </div>
</div>

<!-- Card with accent border -->
<div class="bg-white rounded-xl border-l-4 border-l-skyblue border border-gray-200 p-6">
  <!-- Content -->
</div>

5.2 Buttons

Type Color Usage
Primary Belmont Blue Main actions (“Say Hello,” “Submit Event”)
Secondary White + Blue border Alternative actions (“Learn More,” “Cancel”)
Destructive Belmont Red Delete, remove — use sparingly
Ghost Transparent Subtle actions (“Edit,” “View All”)

Friendly button rules:

<!-- Primary -->
<button class="bg-belmontblue hover:bg-fountainblue text-white px-5 py-2.5 rounded-lg font-medium">
  Say Hello
</button>

<!-- Secondary -->
<button class="bg-white border border-gray-300 text-gray-700 hover:bg-gray-50 px-5 py-2.5 rounded-lg font-medium">
  Cancel
</button>

<!-- Destructive (rare) -->
<button class="bg-belmontred hover:bg-red-800 text-white px-5 py-2.5 rounded-lg font-medium">
  Delete
</button>

5.3 Forms (Where “Sterile” Usually Happens)

Make forms feel like guidance, not compliance:

Pattern Example
Always include helper text “This helps other Champions find you”
Human validation “That email doesn’t look right” vs “Invalid format”
Grouped fields Labeled sections with whitespace
Progressive disclosure Advanced fields behind “Add details” toggle
<!-- Form field with helper text -->
<div class="space-y-1">
  <label class="block text-sm font-medium text-gray-700">City</label>
  <input type="text" class="w-full rounded-lg border-gray-300 focus:border-belmontblue focus:ring-belmontblue" />
  <p class="text-sm text-gray-500">Enter your current city so Champions can find you.</p>
</div>

5.4 Tables (Less Spreadsheet, More Friendly)

Tables are inherently “cold” — soften them:

Pattern Implementation
Zebra striping Very subtle tint (not harsh alternation)
Row padding More generous than default
Empty state Suggests what to do next
Mobile Switch to card rows (name + key fields + actions)

5.5 Empty States (Easy Win for Warmth)

Every empty state should include:

  1. A friendly headline
  2. One sentence of “what this is”
  3. One next-step action (button or link)
  4. Optional: a small icon matching the section

Tone examples:

❌ Bad ✅ Good
“No Champions found.” “No Champions in Portland yet.”
“No messages.” “Your inbox is empty — start a conversation!”
“No events.” “No events scheduled. Want to host one?”
<!-- Empty state example -->
<div class="text-center py-12">
  <%= heroicon "users", variant: :outline, options: { class: "w-12 h-12 text-gray-400 mx-auto" } %>
  <h3 class="mt-4 text-lg font-medium text-gray-900">No Champions in Portland yet</h3>
  <p class="mt-2 text-gray-500">Know an alum there? Invite them to join!</p>
  <button class="mt-4 bg-belmontblue text-white px-4 py-2 rounded-lg">
    Invite a Champion
  </button>
</div>

5.6 Feedback States (Micro-Delight, Not Gimmicks)

State Approach
Loading Skeleton screens for lists/cards (reduces stress)
Success Short confirmation + what happens next
Errors One clear fix, not a wall of red

6. Dashboard Patterns

Implemented in Phase 1.9.4 — The dashboard is the “home” of the Champion Portal.

6.1 Philosophy: Home, Not Admin Panel

The dashboard should feel like returning to a welcoming community space, not logging into a corporate tool.

Admin Panel Feel ❌ Community Home Feel ✅
Generic “Dashboard” title “Good morning, Jane! 👋”
Dense metrics grid Scannable card hierarchy
All sections equal weight Clear visual priority
Static, unchanging Fresh content encourages return
Transactional language Warm, belonging language

6.2 Time-of-Day Greetings

Personalized greetings based on local time create warmth:

Time Range Greeting
5:00 AM – 11:59 AM “Good morning, [Name]! 👋”
12:00 PM – 4:59 PM “Good afternoon, [Name]! 👋”
5:00 PM – 4:59 AM “Good evening, [Name]! 👋”

Implementation: See Cp::DashboardHelper#time_of_day_greeting

<h1 class="font-sansalt text-2xl sm:text-3xl font-bold text-belmontblue">
  <%= time_of_day_greeting(current_cp_champion.display_first_name) %>
</h1>

6.3 New Champion Welcome (First 7 Days)

Champions in their first week get an enhanced welcome hero:

<% if current_cp_champion.created_at > 7.days.ago %>
  <!-- Full welcome banner with gradient -->
<% else %>
  <!-- Simpler returning champion greeting -->
<% end %>

6.4 Widget Hierarchy

Dashboard widgets have clear priority order. Higher priority = larger, more prominent.

Priority Widget Visual Treatment
1. Hero Welcome greeting Full-width, gradient for new users
2. Next Steps Profile/verification prompts Prominent card, consolidated
3. Community District preview Champion photos, location context
4. Messages Unread count + previews Sidebar position, badge for unread
5. Profile Compact summary Sidebar, completion progress
6. News Community content Grid cards (Phase 1.10)
7. Quick Actions Edit, search, invite, help Demoted to subtle row

6.5 Consolidated “Next Steps” Card

Multiple prompts (profile completion, verification pending, location missing) should be consolidated into one card, not scattered across the page.

Card Structure:

Item Types: | Icon | Type | Description | |——|——|————-| | 👤 (profile) | Profile completion | “Complete your profile (85%)” | | ⏳ (clock) | Verification pending | “You’ll get directory access soon” | | 📍 (location) | Missing location | “Add ZIP code to find nearby Champions” |

6.6 Community Context States

The Community Snapshot card adapts to the champion’s state:

State Display
No ZIP code Prompt to add location
Not verified “Directory unlocks after verification” + count
First in district Celebration + invite CTA + regional fallback
Has neighbors Photo preview grid + “View all →”

6.7 News/Posts Section

Design now, implement in Phase 3.3. The dashboard needs fresh content for return visits.

Post Type Icon Example
Story 📰 Alumni Spotlight: Sarah Chen
Photo 📷 Nashville Meetup Recap
Announcement 📢 New Feature: Direct Messaging

Environment-aware display:

<% if show_demo_content? %>
  <!-- Sample news cards -->
<% else %>
  <!-- Coming soon placeholder -->
<% end %>

6.8 Quick Actions (Demoted)

Quick actions are utility, not primary navigation. Display as subtle row at bottom:

<div class="border-t border-gray-200 pt-6">
  <p class="text-xs font-medium text-gray-400 uppercase tracking-wider mb-3">Quick Actions</p>
  <div class="flex flex-wrap gap-2">
    <!-- Ghost-style buttons: Edit Profile, Find Alumni, Invite, Help, Settings -->
  </div>
</div>

6.9 Dashboard Layout (Responsive)

Mobile (< 1024px): Single column, full-width cards stacked vertically.

Desktop (≥ 1024px): 3-column grid:

Desktop Layout:
┌─────────────────────────────────────────────────────────────────┐
│ Hero: Welcome greeting (full width)                             │
├───────────────────────────────────────────┬─────────────────────┤
│ Next Steps (2/3)                          │ Messages (1/3)      │
├───────────────────────────────────────────┼─────────────────────┤
│ Community Snapshot (2/3)                  │ Your Profile (1/3)  │
├───────────────────────────────────────────┴─────────────────────┤
│ News/Posts (full width, 3-card grid)                            │
├─────────────────────────────────────────────────────────────────┤
│ Quick Actions (subtle row, full width)                          │
└─────────────────────────────────────────────────────────────────┘

7. Recognition & Celebration

Activity Indicators

Show who’s active and engaged:

<!-- Active indicator on profile card -->
<div class="relative">
  <img src="..." class="w-12 h-12 rounded-full" />
  <span class="absolute bottom-0 right-0 w-3 h-3 bg-green-500 border-2 border-white rounded-full" 
        title="Active this week"></span>
</div>

Contribution Badges

Badge Trigger
🎉 Event Host Hosted at least 1 event
📖 Storyteller Shared a story
🤝 Connector Sent 5+ messages
⭐ Active Active every week for a month

Welcome Moments

New Champions should feel welcomed:

<!-- Dashboard welcome banner -->
<div class="bg-gradient-to-r from-belmontblue to-admissionsblue text-white rounded-xl p-6">
  <h2 class="text-2xl font-bold">Welcome to the Champion Portal, Sarah! 🎉</h2>
  <p class="mt-2 text-blue-100">You're now connected to 127 Champions across 23 cities.</p>
  <a href="..." class="mt-4 inline-block bg-white text-belmontblue px-4 py-2 rounded-lg font-semibold hover:bg-gray-100">
    Find Champions Near You
  </a>
</div>

Celebration Confetti

For milestone moments (first event submitted, account verified), consider subtle confetti or animation.


8. Mobile-First Polish

See also: Phase 1.17: Mobile Polish for implementation details

8.1 Touch + Reach (Thumb-Zone Aware)

8.2 Navigation Patterns

8.3 Forms on Mobile

8.4 Responsive Breakpoints

Breakpoint Size Design
Mobile < 640px Single column, stacked cards
Tablet 640–1024px Two columns where appropriate
Desktop > 1024px Full layout, sidebars

8.5 Fixed Bottom Nav Padding

The Champion Portal uses a fixed bottom navigation bar on mobile. All pages must account for this by adding bottom padding to the main content area:

<%# In layout or main content wrapper %>
<main class="pb-20 sm:pb-0">
  <%# Content won't be hidden behind bottom nav %>
</main>

8.6 Card Margins & Padding

Standardize card styling across all views:

Property Mobile Desktop
Horizontal margin mx-4 (16px) mx-0 (in grid)
Internal padding p-4 (16px) p-6 (24px)
Section spacing space-y-4 space-y-6
<%# Standard card pattern %>
<div class="mx-4 sm:mx-0">
  <div class="bg-white rounded-xl shadow-sm p-4 sm:p-6">
    <%# Card content %>
  </div>
</div>

8.7 Collapsible Filters

On mobile, filter-heavy views (Directory, Events) should collapse filters by default:

┌─────────────────────────────────┐
│ Filters (2 applied)        [▼] │
└─────────────────────────────────┘

8.8 Hero Section Guidelines

Hero sections should inform, not dominate. On mobile:

Guideline Rule
Max viewport height ~35% of initial viewport
Hero padding py-4 sm:py-8 (reduced on mobile)
Action buttons Move outside hero on mobile
Photo size w-20 h-20 mobile, w-24 h-24 desktop

Use consistent back navigation across all detail views:

<%# app/views/shared/_back_link.html.erb %>
<%= link_to path, class: "inline-flex items-center gap-1 text-gray-600 hover:text-belmontblue text-sm mb-4" do %>
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
  </svg>
  Back to <%= section_name %>
<% end %>

Rules:

8.10 Text Truncation

Handle long text gracefully:

Content Type Strategy Tailwind Class
Names (single line) Truncate with ellipsis truncate
Descriptions 2-line clamp line-clamp-2
Community names Allow 2-line wrap line-clamp-2

8.11 Admin Portal Mobile Patterns

Context: The Alumni Lookup admin portal (.alumnilookup.com/champions/) uses tables for data-heavy views. These tables are replaced with mobile card views on small screens.

Table → Card Pattern

For index/list pages with data tables:

<%# 1. Mobile Card Container (visible on mobile only) %>
<div class="sm:hidden mt-6 space-y-3">
  <% @items.each do |item| %>
    <%# Link wrapper makes entire card clickable %>
    <%= link_to item_path(item), class: "block bg-white rounded-lg shadow-sm ring-1 ring-gray-900/5 p-4 hover:bg-gray-50" do %>
      <div class="flex items-start gap-3">
        <%# Left: Image/Avatar %>
        <div class="w-12 h-12 rounded-lg bg-gray-100 flex-shrink-0">
          <%# Image or placeholder %>
        </div>
        
        <%# Center: Primary info %>
        <div class="flex-1 min-w-0">
          <span class="font-medium text-gray-900 truncate"><%= item.title %></span>
          <p class="text-sm text-gray-500"><%= item.subtitle %></p>
          <p class="text-xs text-gray-400 mt-1">📍 <%= item.location %></p>
        </div>
        
        <%# Right: Chevron %>
        <svg class="w-5 h-5 text-gray-400 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
        </svg>
      </div>
      
      <%# Bottom: Badges/metadata row %>
      <div class="flex flex-wrap items-center gap-2 mt-3 pt-3 border-t border-gray-100">
        <span class="badge">Status</span>
        <span class="text-xs text-gray-400 ml-auto">Date</span>
      </div>
    <% end %>
  <% end %>
  
  <%# Mobile-specific pagination and empty state here %>
</div>

<%# 2. Desktop Table (hidden on mobile) %>
<div class="hidden sm:block mt-6 bg-white shadow overflow-hidden rounded-lg">
  <table class="min-w-full divide-y divide-gray-200">
    <%# ... existing table markup ... %>
  </table>
</div>

Card Layout Rules

Element Class Purpose
Container sm:hidden mt-6 space-y-3 Mobile only, vertical spacing
Card block bg-white rounded-lg shadow-sm ring-1 ring-gray-900/5 p-4 hover:bg-gray-50 Clickable, elevated
Image/Avatar w-12 h-12 rounded-lg flex-shrink-0 Consistent size, no shrink
Title font-medium text-gray-900 truncate Bold, truncate long names
Subtitle text-sm text-gray-500 Secondary info
Metadata text-xs text-gray-400 Timestamps, locations
Chevron w-5 h-5 text-gray-400 flex-shrink-0 Indicates tappable
Badge row flex flex-wrap items-center gap-2 mt-3 pt-3 border-t Bottom section

Status Badge Classes (Admin)

<%# Published/Active/Complete %>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
  Published
</span>

<%# Pending/Draft %>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
  Draft
</span>

<%# Archived/Inactive %>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800">
  Archived
</span>

<%# Rejected/Error %>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
  Rejected
</span>

Emoji Shorthand (Admin Cards)

Use emoji sparingly to convey context at a glance:

Emoji Meaning Example
📅 Event 📅 Nashville Meetup
📍 Location/District 📍 Nashville
🌐 Community 🌐 Music Business
📷 Photo count 📷 12 photos
Featured count ⭐ 3 featured
💬 Comments/replies 💬 5 replies
👤 Person 👤 Jane Smith

Show Page Button Patterns

For detail/show pages in admin portal:

<%# Action buttons should stack on mobile %>
<div class="flex flex-col sm:flex-row gap-2 sm:gap-3">
  <%# Primary action %>
  <%= link_to "Primary Action", action_path,
      class: "inline-flex items-center justify-center gap-2 px-4 py-2 bg-belmontblue text-white rounded-lg hover:bg-fountainblue transition text-center" %>
  
  <%# Secondary action %>
  <%= link_to "Secondary", other_path,
      class: "inline-flex items-center justify-center gap-2 px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition text-center" %>
  
  <%# Destructive action (if needed) %>
  <%= button_to "Delete", destroy_path, method: :delete,
      data: { turbo_confirm: "Are you sure?" },
      class: "inline-flex items-center justify-center gap-2 px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition text-center" %>
</div>

Rules:

Reference Implementations

Page Type Reference File
Index with cards champions/events/index.html.erb
Index with complex data champions/champions/_list.html.erb
Show page buttons champions/feedbacks/show.html.erb
Show page with stats champions/communities/show.html.erb
Discussions with moderation champions/discussions/show.html.erb
Photo albums with actions champions/photo_albums/show.html.erb

Model Method Naming (Critical)

Problem: Calling model.verified? fails because enum methods follow a specific naming pattern.

Pattern: For enum columns, Rails generates status_<value>? methods, NOT <value>? methods.

❌ Wrong ✅ Correct Why
champion.verified? champion.status_champion_verified? Enum column is status with value champion_verified
event.published? event.status_published? Same pattern

How to check: Look at the model’s enum definition:

# In model
enum :status, { pending: 0, champion_verified: 1, rejected: 2 }

# Generated methods
champion.status_pending?
champion.status_champion_verified?
champion.status_rejected?

Index Card Routing (Critical)

Problem: Index cards that link to show action fail when show action doesn’t exist.

Pattern: Check if the resource has a show action. If except: [:show], link to edit instead.

Resource Routes Declaration Card Links To
Events resources :events, except: [:show] edit_champions_event_path(event)
Communities resources :communities (has show) champions_community_path(community)
Discussions resources :discussions (has show) champions_discussion_path(discussion)

How to verify:

bin/rails routes | rg "champions_events"
# Look for GET /champions/events/:id — if missing, no show action

Text Truncation Patterns

Problem: Aggressive truncation like truncate max-w-[120px] cuts off content too aggressively.

Pattern: Use line-clamp-n for multi-line text, allow reasonable width.

Content Type Pattern Example
Card titles line-clamp-2 <span class="font-medium text-gray-900 line-clamp-2">
Community badges max-w-[200px] line-clamp-1 Allows longer names but caps at 200px
Descriptions line-clamp-3 to line-clamp-5 Adjust based on layout
Names min-w-0 on container + line-clamp-2 Prevents flex overflow

Rules:

Show Page Header Patterns

Problem: Headers with photo + name + buttons crunch on mobile.

Pattern: Use flex-col on mobile, flex-row on desktop.

<%# Header container %>
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
  <%# Left side: photo + info %>
  <div class="flex items-center gap-4">
    <%# Photo - prevent shrinking %>
    <div class="flex-shrink-0">
      <img class="w-16 h-16 rounded-full object-cover" />
    </div>
    
    <%# Info - allow truncation %>
    <div class="min-w-0">
      <h1 class="text-2xl font-bold text-gray-900 line-clamp-2"><%= item.name %></h1>
      <p class="text-gray-500 line-clamp-1"><%= item.subtitle %></p>
    </div>
  </div>
  
  <%# Right side: action buttons %>
  <div class="flex flex-wrap gap-2">
    <%# Buttons here %>
  </div>
</div>

Key classes:

Action Button Styling (Show Pages)

Pattern: Icons + short labels, color-coded by action type, stack on mobile.

<div class="flex flex-col sm:flex-row flex-wrap gap-2">
  <%# Edit - gray %>
  <%= link_to edit_path, class: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200" do %>
    <svg class="w-4 h-4"><!-- pencil icon --></svg>
    Edit
  <% end %>
  
  <%# Toggle visibility - gray/green %>
  <%= button_to toggle_path, class: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-lg #{item.hidden? ? 'bg-green-100 text-green-700 hover:bg-green-200' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'}" do %>
    <svg class="w-4 h-4"><!-- eye icon --></svg>
    <%= item.hidden? ? "Show" : "Hide" %>
  <% end %>
  
  <%# Lock - yellow %>
  <%= button_to lock_path, class: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-lg bg-yellow-100 text-yellow-700 hover:bg-yellow-200" do %>
    <svg class="w-4 h-4"><!-- lock icon --></svg>
    <%= item.locked? ? "Unlock" : "Lock" %>
  <% end %>
  
  <%# Delete - red %>
  <%= button_to destroy_path, method: :delete, class: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-lg bg-red-100 text-red-700 hover:bg-red-200" do %>
    <svg class="w-4 h-4"><!-- trash icon --></svg>
    Delete
  <% end %>
  
  <%# External link - white with ring %>
  <%= link_to external_url, target: "_blank", class: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-lg bg-white text-gray-700 ring-1 ring-gray-300 hover:bg-gray-50" do %>
    <svg class="w-4 h-4"><!-- external link icon --></svg>
    View
  <% end %>
</div>

Color coding: | Action Type | Background | Text | Hover | |————-|————|——|——-| | Edit/Default | bg-gray-100 | text-gray-700 | hover:bg-gray-200 | | Show/Restore | bg-green-100 | text-green-700 | hover:bg-green-200 | | Lock/Caution | bg-yellow-100 | text-yellow-700 | hover:bg-yellow-200 | | Resolve/Special | bg-purple-100 | text-purple-700 | hover:bg-purple-200 | | Delete/Danger | bg-red-100 | text-red-700 | hover:bg-red-200 | | External | bg-white ring-1 ring-gray-300 | text-gray-700 | hover:bg-gray-50 |

Section Headers with Actions (CRITICAL)

Problem: Section headers with action buttons use flex items-center justify-between, which keeps the button stuck to the right of the header text even on mobile, causing cramped layouts.

Pattern: Use flex-col on mobile, flex-row on desktop for section headers with actions.

<%# ❌ WRONG: Button stays right of header on all screen sizes %>
<div class="flex items-center justify-between">
  <h3 class="text-lg font-medium">Section Title</h3>
  <%= link_to "Action", path, class: "..." %>
</div>

<%# ✅ CORRECT: Button stacks below header on mobile, beside on desktop %>
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
  <h3 class="text-lg font-medium">Section Title</h3>
  <%= link_to "Action", path, class: "inline-flex items-center justify-center ..." %>
</div>

Rules:

Danger Zone Pattern (Show Pages)

Problem: Destructive actions (Deactivate, Delete) placed in the header with other buttons makes them too easy to click accidentally and clutters the header.

Pattern: Place destructive actions in a “Danger Zone” section at the bottom of show pages.

<!-- Danger Zone -->
<div class="mt-8 bg-white shadow overflow-hidden sm:rounded-lg border border-red-200">
  <div class="px-4 py-5 sm:px-6 border-b border-red-200 bg-red-50">
    <h3 class="text-lg font-medium text-red-900">Danger Zone</h3>
    <p class="text-sm text-red-700">Irreversible and destructive actions</p>
  </div>
  <div class="px-4 py-5 sm:px-6">
    <div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
      <div>
        <p class="text-sm font-medium text-gray-900">Action title</p>
        <p class="text-sm text-gray-500">Description of what this action does.</p>
      </div>
      <%= button_to "Destructive Action", path, 
                    method: :patch,
                    class: "inline-flex items-center justify-center px-4 py-2 border border-red-300 shadow-sm text-sm font-medium rounded-md text-red-700 bg-white hover:bg-red-50",
                    data: { turbo_confirm: "Are you sure?" } %>
    </div>
  </div>
</div>

Rules:

Admin Show Page Card Structure

Problem: Inconsistent card styling and section organization across admin show pages.

Pattern: Each major section should be its own card with consistent styling.

<%# Standard admin card %>
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
  <%# Card header %>
  <div class="px-4 py-5 sm:px-6 border-b border-gray-200">
    <div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
      <h3 class="text-lg font-medium text-gray-900">Section Title</h3>
      <%# Optional action button %>
      <%= link_to "Action", path, class: "..." %>
    </div>
  </div>
  
  <%# Card content %>
  <div class="px-4 py-5 sm:px-6">
    <%# Section content here %>
  </div>
</div>

Principles:


8.12 Admin Card & Container Standards (CRITICAL)

Problem: Inconsistent card classes and redundant container wrappers across admin views make the interface feel disjointed.

Container Rules

The layout (application.html.erb) already provides:

Therefore, admin views should NOT add redundant wrappers:

<%# ❌ WRONG: Redundant wrapper (layout already provides this) %>
<div class="px-4 sm:px-6 lg:px-8">
  <div class="py-6">
    <!-- content -->
  </div>
</div>

<%# ✅ CORRECT: Content starts directly, no wrapper needed %>
<!-- Page header -->
<div class="sm:flex sm:items-center sm:justify-between">
  <h1 class="text-2xl font-semibold text-gray-900">Page Title</h1>
</div>

<!-- Card content -->
<div class="mt-6 bg-white shadow overflow-hidden rounded-md sm:rounded-lg">
  <!-- ... -->
</div>

When to use max-w-* constraints:

Standard Card Pattern

All admin cards use this exact pattern:

<div class="bg-white shadow overflow-hidden rounded-md sm:rounded-lg">
  <!-- Card content -->
</div>
Class Purpose
bg-white White background
shadow Subtle elevation (NOT shadow-sm)
overflow-hidden Required for tables and rounded corners
rounded-md sm:rounded-lg Responsive rounding — 8px on mobile, 12px on tablet+

Responsive Card Rounding (CRITICAL)

All cards MUST use rounded-md sm:rounded-lg — not just sm:rounded-lg.

Pattern Mobile Desktop Use Case
rounded-md sm:rounded-lg 8px corners 12px corners ✅ Standard admin cards
sm:rounded-lg only Square corners 12px corners ❌ Avoid — harsh on mobile
rounded-lg only 12px corners 12px corners ❌ Avoid — inconsistent with full-bleed pattern

Why this matters: Cards without mobile rounding appear harsh and “boxy” on small screens. The rounded-md provides subtle softening while sm:rounded-lg gives more pronounced rounding on larger screens where there’s more visual space.

Never use these inconsistent variants: | ❌ Don’t Use | ✅ Use Instead | |————–|—————-| | sm:rounded-lg (no mobile rounding) | rounded-md sm:rounded-lg | | rounded-lg (always same) | rounded-md sm:rounded-lg | | rounded-xl | rounded-md sm:rounded-lg | | shadow-sm | shadow | | ring-1 ring-gray-900/5 | Just shadow | | border border-gray-200 | Just shadow (unless it’s a special case like Danger Zone) |

Card with Header Pattern

<div class="bg-white shadow overflow-hidden rounded-md sm:rounded-lg">
  <%# Header %>
  <div class="px-4 py-5 sm:px-6 border-b border-gray-200">
    <div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
      <h3 class="text-lg font-medium text-gray-900">Section Title</h3>
      <%= link_to "Action", path, class: "..." %>
    </div>
  </div>
  
  <%# Body %>
  <div class="px-4 py-5 sm:px-6">
    <!-- Content -->
  </div>
</div>

Card Inner Padding Standards

Context Padding Class
Card header px-4 py-5 sm:px-6
Card body px-4 py-5 sm:px-6
Stats grid px-4 py-5 sm:p-6
Table container No padding (table handles it)
Form content p-6 (simpler for forms)

Desktop Table vs Mobile Cards Pattern

<%# Mobile cards (hidden on desktop) %>
<div class="sm:hidden mt-6 space-y-3">
  <% @items.each do |item| %>
    <%= link_to item_path(item), class: "block bg-white rounded-lg shadow-sm ring-1 ring-gray-900/5 p-4 hover:bg-gray-50" do %>
      <!-- Mobile card content -->
    <% end %>
  <% end %>
</div>

<%# Desktop table (hidden on mobile) %>
<div class="hidden sm:block mt-6 bg-white shadow overflow-hidden rounded-md sm:rounded-lg">
  <table class="min-w-full divide-y divide-gray-200">
    <!-- Table content -->
  </table>
</div>

Note: Mobile cards use ring-1 ring-gray-900/5 for a lighter touch, while desktop tables use the standard shadow for stronger elevation.

Page Structure Template (Admin)

<%# Page header %>
<div class="sm:flex sm:items-center sm:justify-between">
  <div>
    <h1 class="text-2xl font-semibold text-gray-900">Page Title</h1>
    <p class="mt-1 text-sm text-gray-500">Optional description</p>
  </div>
  <div class="mt-4 sm:mt-0">
    <%= link_to "Action", path, class: "..." %>
  </div>
</div>

<%# Stats (optional) %>
<div class="mt-6 grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
  <div class="bg-white shadow overflow-hidden rounded-md sm:rounded-lg px-4 py-5 sm:p-6">
    <!-- Stat content -->
  </div>
</div>

<%# Main content card %>
<div class="mt-6 bg-white shadow overflow-hidden rounded-md sm:rounded-lg">
  <!-- Content -->
</div>

<%# Additional sections with consistent spacing %>
<div class="mt-8 bg-white shadow overflow-hidden rounded-md sm:rounded-lg">
  <!-- Another section -->
</div>

<%# Danger Zone (always last, if applicable) %>
<div class="mt-8 bg-white shadow overflow-hidden rounded-md sm:rounded-lg border border-red-200">
  <!-- Danger zone content -->
</div>

Spacing Between Elements

Context Spacing Class
Header to first card mt-6
Between cards mt-8
Between form sections mt-6
Mobile card list items space-y-3

8.13 Mobile Optimization Checklist (COMPREHENSIVE)

When someone says “this page needs to be mobile optimized,” use this checklist.

This is the definitive reference for what “mobile optimized” means in this project. The previous subsections (8.1–8.12) cover implementation patterns; this section provides the complete evaluation framework.

The Litmus Test

Before diving into the checklist, apply this simple test:

“Do one thing here, quickly, while distracted.”

Ask yourself:

If any answer is “no” or “maybe,” the page needs work.


Category 1: Layout & Structure

Goal: Content flows naturally in a single column; nothing feels cramped or requires horizontal scrolling.

✅ Requirement Notes
Single-column layout on mobile No side-by-side columns that crunch content
No horizontal scrolling Tables convert to cards; wide content wraps or scrolls within container
Logical vertical stacking Most important content first; actions near related content
Adequate breathing room py-4, space-y-4 minimum between sections
Full-bleed cards on mobile Cards go edge-to-edge (no mx-4 margins creating gutters)

🚩 Red flags:


Category 2: Touch & Interaction

Goal: Every interactive element is easy to tap accurately on the first try.

✅ Requirement Notes
Minimum 44×44px tap targets Buttons, links, checkboxes, dropdown triggers
8px+ spacing between targets Prevent accidental taps on adjacent elements
Primary actions in thumb zone Bottom half of screen, reachable without stretching
No hover-dependent interactions All hover states must have tap/touch equivalents
Clear active/pressed states Visual feedback on tap (not just release)

🚩 Red flags:


Category 3: Navigation & Wayfinding

Goal: Users always know where they are and how to go back.

✅ Requirement Notes
Clear page/section titles Visible without scrolling
Back navigation consistent Use "← Back to [Section]" pattern from §8.9
Tab bars/pills scroll gracefully Long tab lists wrap or scroll horizontally with indicators
Bottom nav doesn’t obscure content Add pb-20 to main content when using fixed bottom nav
Current location highlighted Active nav item visually distinct

🚩 Red flags:


Category 4: Typography & Readability

Goal: Text is comfortable to read on a phone screen.

✅ Requirement Notes
Base font size 16px+ Prevents iOS zoom on focus; comfortable reading
Line height 1.5+ for body text leading-relaxed or leading-loose
Headings scale proportionally text-xl mobile → text-2xl desktop, not fixed sizes
Max 80 characters per line Use max-w-prose or similar constraint
Sufficient contrast WCAG AA (4.5:1 for body, 3:1 for large text)

🚩 Red flags:


Category 5: Content Hierarchy & Priority

Goal: The most important action/information is immediately obvious.

✅ Requirement Notes
One clear primary action per screen Button hierarchy: one primary, others secondary/ghost
Key info visible without scrolling Name, status, primary action above the fold
Progressive disclosure for details Expandable sections, “Show more” patterns
Metadata grouped and de-emphasized Dates, counts, IDs in smaller/muted text
Empty states guide next action Never just “No results” — always suggest what to do

🚩 Red flags:


Category 6: Forms & Inputs

Goal: Forms are easy to complete on mobile without frustration.

✅ Requirement Notes
One column layout for forms Never side-by-side fields on mobile
Correct keyboard type type="email", type="tel", inputmode="numeric"
Labels above inputs (not beside) Labels stay visible when field is focused
Large, tappable checkboxes/radios 44px touch target including label
Clear error states Inline errors near the field, not just top of form
Submit button always visible Consider sticky footer or position after last field

🚩 Red flags:


Category 7: Lists, Tables & Data Density

Goal: Data is scannable and actionable without overwhelming the screen.

✅ Requirement Notes
Tables convert to cards on mobile Use sm:hidden / hidden sm:block pattern from §8.11
Row actions accessible without scroll Show on card, or in overflow menu
Pagination or infinite scroll Don’t load 100+ items at once
Sort/filter controls accessible Collapse into filter button if needed
Key columns visible Hide low-priority columns on mobile, not primary data

🚩 Red flags:


Category 8: Performance & Load Behavior

Goal: The page feels fast, even on slow connections.

✅ Requirement Notes
Appropriate image sizes Don’t send 2000px images for 80px thumbnails
Lazy loading for below-fold content Images, cards, comments
Skeleton/placeholder states Show structure while content loads
No layout shift on load Reserve space for images, dynamic content
Turbo Frame/Stream for partial updates Don’t reload full page for small changes

🚩 Red flags:


Category 9: Accessibility (Mobile-Specific)

Goal: The page works for users with different abilities and assistive technologies.

✅ Requirement Notes
Focus order matches visual order Tab through the page in logical sequence
Focus states visible focus:ring-2 focus:ring-belmontblue minimum
Touch targets meet WCAG AA 44×44px minimum
Screen reader announces state changes Use ARIA live regions for dynamic updates
No essential info in color alone Icons, text, or patterns supplement color

🚩 Red flags:


Category 10: Visual Tone & Comfort

Goal: The mobile experience feels warm and inviting, not cramped or sterile.

✅ Requirement Notes
Adequate whitespace Cards have padding; sections have margins
Warm neutrals, not cold grays gray-50 backgrounds, not pure white everywhere
Rounded corners on cards rounded-lg or rounded-xl for touch-friendly feel
Consistent iconography Same icon set; icons aid comprehension
No “admin density” on user-facing pages Champions aren’t power users; give them room

🚩 Red flags:


Quick Audit Workflow

When auditing a page for mobile optimization:

  1. Open on real phone (or DevTools mobile view at 375px width)
  2. Apply the Litmus Test — Can I do one thing, quickly, while distracted?
  3. Walk through Categories 1-10 — Note any red flags
  4. Tap every interactive element — Is it easy to hit? Does it respond?
  5. Scroll the entire page — Does content flow? Anything cramped?
  6. Check with keyboard/VoiceOver — Focus order logical? Announcements clear?

For implementation details on specific patterns, see:


9. Accessibility

Requirements

Requirement Standard
Color contrast WCAG AA minimum (4.5:1 for text)
Focus states Visible keyboard focus indicators
Alt text All images must have descriptive alt text
ARIA labels Interactive elements need accessible names
Skip links Navigation skip for keyboard users

Note: The Belmont digital brand colors are designed with screen contrast in mind.

Testing


10. Implementation Notes

Tailwind-Friendly Defaults

These are “defaults” to keep us consistent:

Element Default
Border radius rounded-lg for inputs, sm:rounded-lg for admin cards
Card shadow shadow for admin cards (not shadow-sm)
Borders Low-contrast (border-gray-200), avoid heavy outlines
Page background Warm neutral (bg-gray-50 or custom warm)
Card background bg-white with shadow overflow-hidden sm:rounded-lg

Note: Champion Portal (user-facing) may use rounded-xl shadow-sm for cards. Admin Portal uses sm:rounded-lg shadow for a more data-focused appearance.

When a Page Feels Sterile

Fix in this order:

  1. Whitespace and grouping — Add section breaks, reduce clutter
  2. Surface tint and shadows — Warm backgrounds, soft depth
  3. Typography size/line-height — Bigger, more comfortable text
  4. Icons and section accents — Visual landmarks
  5. Only then consider adding more color

Image Variant Sizing (Critical for Sharp Images)

Key Principle: Image variant dimensions must match CSS display dimensions to avoid fuzzy images.

When using variant(resize_to_fill: [width, height]), the pixel values should match the actual rendered size:

Tailwind Class Pixels Variant Size
w-14 h-14 56×56 resize_to_fill: [56, 56]
w-20 h-20 80×80 resize_to_fill: [80, 80]
w-24 h-24 96×96 resize_to_fill: [96, 96]
w-28 h-28 112×112 resize_to_fill: [112, 112]
w-32 h-32 128×128 resize_to_fill: [128, 128]
w-40 h-40 160×160 resize_to_fill: [160, 160]
w-48 h-48 192×192 resize_to_fill: [192, 192]

Rectangular images: For non-square displays, use rectangular variants:

Common mistakes: | ❌ Wrong | ✅ Correct | Issue | |———-|———–|——-| | resize_to_fill: [128, 128] for w-28 | resize_to_fill: [112, 112] | Oversized → wasted bandwidth | | resize_to_fill: [112, 112] for rectangular display | resize_to_fill: [128, 96] | Square for rectangle → fuzzy upscaling | | resize_to_fill: [800, 500] for aspect-video | resize_to_fill: [800, 450] | 8:5 ratio for 16:9 container → cropping |

Color Classes Reference

/* Configured in tailwind.config.js */
belmontblue: '#001D54'    /* Primary anchor */
belmontred: '#B21029'     /* Secondary emphasis */
admissionsblue: '#1D4289' /* Alt primary */
fountainblue: '#2874AF'   /* Hover states */
skyblue: '#6AB3E7'        /* Highlights */
towerred: '#862633'       /* Legacy - prefer belmontred */

11. Image Request Checklist

Standard Practice: Image Placeholders

When building pages, always include explicit image placeholders with requests:

<!-- Example placeholder in ERB -->
<div class="relative bg-gray-200 rounded-lg overflow-hidden" style="aspect-ratio: 16/9;">
  <div class="absolute inset-0 flex items-center justify-center text-gray-500">
    <div class="text-center p-4">
      <svg class="w-12 h-12 mx-auto mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 
              d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
      </svg>
      <p class="font-medium">IMAGE NEEDED</p>
      <p class="text-sm">Hero: Campus bell tower at sunset</p>
      <p class="text-xs">1920x600px, landscape, space for text overlay on left</p>
    </div>
  </div>
</div>

For Hero/Header Images

For City Images

For Activity/People Images

Example Request

Image Request: Champion Portal Hero Image

Purpose: Landing page hero for alumnichampions.com
Dimensions: 1920×600px (will be cropped responsively)
Subject: Belmont campus with alumni, ideally near bell tower or lawn
Mood: Warm, welcoming, aspirational
Text overlay: Yes — need space on left side for headline
Notes: Avoid dated clothing or event-specific signage


Document Purpose
LANGUAGE_STYLE_GUIDE.md Voice & tone for all copy — Required for any user-facing text
../JOBS-TO-BE-DONE.md User motivations (esp. Job C9: Feel Like I Belong)
../STAKEHOLDER-OVERVIEW.md High-level features and strategic context
../phases/phase-1/1.9-pre-beta-polish.md Visual refresh implementation
../phases/phase-4/README.md Mobile polish planning
tailwind.config.js Color configuration
Belmont Brand Guidelines Official brand guidelines

Quick Reference: The Golden Rules

  1. Belmont Blue anchors, Belmont Red emphasizes — Not the other way around
  2. Expanded palette ≤30% — Blue and neutrals do the heavy lifting
  3. Warm neutrals over cold grays — Off-white, not pure white
  4. Fix sterility with spacing first — Then surfaces, then typography, then color
  5. Every empty state invites action — Never leave users stranded
  6. Mobile-first, always — Thumb zones matter

This document should evolve as we build. Add patterns that work, remove patterns that don’t.