unparty-app UI Standards

Centralized reference for fonts, colors, layouts, and code snippets. Use this doc to build consistent UI fast.

“See also: styling-project.md (Tailwind architecture), src/app/theunpartytemplate/STYLE.md (iOS design system)”

---

Table of Contents

---

Brand Colors

Defined in src/app/constants/colors.ts.

Core Brand Palette

Name
brand
Hex
#F9C22E
Usage
Signature yellow — primary brand accent, interactive highlights

Extended Palette

Name
electricPurple
Hex
#3500D3
Character
Vivid purple accent

Usage in Code

ts
// Import all colors
import { colors, palette } from '@/app/constants/colors';

// Inline style (dynamic theming)
<div style={{ color: colors.brand }}>...</div>

// Dynamic theme color via hook
import { useTheme } from '@/app/contexts/ThemeContext';
const { colorValue } = useTheme();
<div style={{ color: colorValue }}>...</div>

---

CSS Design Tokens

Defined in src/app/globals.css as CSS custom properties.

Base Colors (Light / Dark)

css
/* Light mode */
--background:            #ededed;
--foreground:            #171717;
--background-highlight:  rgba(0, 0, 0, 0.1);
--text-muted:            rgba(23, 23, 23, 0.8);

/* Dark mode (auto-applied via @media prefers-color-scheme: dark) */
--background:            #0a0a0a;
--foreground:            #ededed;
--background-highlight:  rgba(255, 255, 255, 0.1);
--text-muted:            rgba(237, 237, 237, 0.8);

Tailwind aliases (configured in tailwind.config.ts):

tsx
// These resolve to the CSS variables above
className="bg-background text-foreground bg-background-highlight"

Depth / Shadow System

Use these to create visual hierarchy — prefer CSS vars over custom box-shadow values.

css
--depth-raised:   0 2px 4px rgba(0, 0, 0, 0.1);    /* Slightly lifted element */
--depth-elevated: 0 4px 8px rgba(0, 0, 0, 0.12);   /* Hover state / card */
--depth-floating: 0 6px 12px rgba(0, 0, 0, 0.15);  /* Sticky elements */
--depth-modal:    0 8px 16px rgba(0, 0, 0, 0.15);  /* Modals / drawers */
--depth-overlay:  0 12px 24px rgba(0, 0, 0, 0.18); /* Dropdowns / overlays */
tsx
// Usage example
<div style={{ boxShadow: 'var(--depth-elevated)' }}>...</div>

Brand Shadow & Glow

css
--brand-shadow:        0 2px 4px rgba(249, 194, 46, 0.1);
--brand-shadow-strong: 0 4px 8px rgba(249, 194, 46, 0.15);
--brand-glow:          0 0 8px rgba(249, 194, 46, 0.2);
--brand-glow-strong:   0 0 12px rgba(249, 194, 46, 0.25);
--brand-accent:        rgba(249, 194, 46, 0.1);
--brand-accent-strong: rgba(249, 194, 46, 0.15);

Interactive State Tokens

css
--focus-ring:        0 0 0 3px rgba(249, 194, 46, 0.3);
--hover-lift:        translateY(-1px);
--hover-lift-strong: translateY(-2px);
--active-press:      translateY(0) scale(0.98);

---

Font System

All fonts are configured in src/app/fonts.ts, tailwind.config.ts, and src/app/globals.css.

Available Font Families

Tailwind Class
font-mono
Font
System monospace
CSS Variable
built-in
Character
Code, data, stats
Weights
any

“Local fonts (loaded in src/app/layout.tsx): GeistVF.woff → --font-geist-sans, GeistMonoVF.woff → --font-geist-mono”

Font Usage Examples

tsx
// Most common: monospace for data, stats, labels
<span className="font-mono text-sm">30+</span>

// Rounded / friendly headings
<h1 className="font-rounded text-2xl font-bold">UNPARTY</h1>

// Retro / editorial accent
<span className="font-vt323 text-4xl">STATUS: LIVE</span>

// Modern editorial
<p className="font-space-grotesk text-base font-medium">Description text</p>

---

Layout Patterns

Standard Page Container

The primary page pattern — used across most pages:

tsx
<div className="mx-auto w-full max-w-5xl">
  <div className="flex flex-col gap-6">
    {/* Page content here */}
  </div>
</div>

Page Container with Padding

For pages that need horizontal padding on smaller screens:

tsx
<div className="mx-auto w-full max-w-5xl px-4 sm:px-6">
  <div className="flex flex-col gap-6">
    {/* Page content here */}
  </div>
</div>

Full-Width Section with Centered Content

tsx
<main className="flex flex-col items-center gap-4 pt-2">
  <div className="w-full flex flex-col gap-4 px-2 md:gap-6">
    {/* Full-width content */}
  </div>
</main>

Max-Width Reference

Class
max-w-sm
Width
24rem / 384px
Best For
Compact forms, small cards

Two-Column Grid

tsx
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
  <div>Left</div>
  <div>Right</div>
</div>

Three-Column Grid (responsive)

tsx
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
  {items.map(item => <Card key={item.id} {...item} />)}
</div>

Card / Panel

tsx
<div className="rounded-xl bg-gray-50 p-6 dark:bg-black/10">
  {/* Card content */}
</div>

Card with Brand Glow

tsx
<div
  className="rounded-xl bg-gray-50 p-6 dark:bg-black/10"
  style={{ boxShadow: 'var(--brand-glow)' }}
>
  {/* Card content */}
</div>

---

Typography Utilities

Text Size Scale

Class
text-xs
Size
0.75rem
Common Use
Labels, metadata, timestamps

Common Text Patterns

tsx
// Section label / category tag
<span className="font-mono text-xs font-bold uppercase tracking-wider opacity-60">
  CATEGORY
</span>

// Stat / number
<div className="font-mono text-lg font-bold" style={{ color: colorValue }}>
  42+
</div>

// Body paragraph
<p className="text-sm leading-relaxed opacity-80">
  Description text goes here.
</p>

// Prominent heading
<h2 className="font-rounded text-2xl font-bold">
  Section Title
</h2>

// Brand-colored inline highlight
<span className="font-bold" style={{ color: colors.brand }}>
  highlighted term
</span>

// Keyword term (uses .keyword-term CSS class from globals.css)
<span className="keyword-term">clickable term</span>

---

Component Snippets

Scroll Row Section

Used to display a horizontally scrolling row with a title and optional "more" link:

tsx
import ScrollRow from '@/components/HorizontalRow';
import PageAsterisk from '@/app/components/PageAsterick';

<ScrollRow
  title="SECTION TITLE"
  items={[
    <PageAsterisk key="asterisk" />,
    // Add components here
  ]}
  moreLink="/more"
  maxItems={4}
/>

Stats Component

tsx
import Stats from '@/app/components/Stats';

// Default values
<Stats />

// Custom values
<Stats waitlistCount={275} vibeMood="HIGH." priorityCategory="HIGH" className="shadow-lg" />

Page with Standard Layout (full example)

tsx
import AboutComponent from '@/app/components/AboutComponent';

export default function MyPage() {
  return (
    <main className="flex flex-col items-center gap-4 pt-2">
      <div className="mx-auto w-full max-w-5xl">
        <div className="flex flex-col gap-6">
          <AboutComponent />
        </div>
      </div>
    </main>
  );
}

Theme-Colored Element

tsx
'use client';
import { useTheme } from '@/app/contexts/ThemeContext';

export default function MyComponent() {
  const { colorValue } = useTheme();
  return (
    <div style={{ borderColor: colorValue, color: colorValue }}>
      Dynamic themed content
    </div>
  );
}

Responsive Section with Gap Scaling

tsx
<section className="flex flex-col gap-4 md:gap-6 lg:gap-8">
  {/* Content */}
</section>

---

Animation & Transitions

Transition Speed Tokens

css
--transition-fast:     0.15s ease;   /* Button hover, micro-interactions */
--transition-standard: 0.2s ease;    /* Most interactive states */
--transition-slow:     0.3s ease;    /* Page transitions, modals */

Custom Easing

css
--easing-brand:  cubic-bezier(0.25, 0.46, 0.45, 0.94);  /* Smooth brand motion */
--easing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55); /* Playful bounce */

CSS Utility Classes (from globals.css)

tsx
// Scrolling banner / chyron
<div className="animate-scroll">
  Scrolling text content
</div>

// Page enter animation (auto-applied inside .page-transition-wrapper)
<div className="page-transition-wrapper">
  {children}
</div>

Standard Hover Pattern (Tailwind)

tsx
// Lift on hover, press on active
<button className="transition-transform duration-150 hover:-translate-y-0.5 active:scale-[0.98]">
  Click me
</button>

---

Dark Mode

The app uses @media (prefers-color-scheme: dark) for automatic dark mode. All CSS variable tokens update automatically.

Patterns

tsx
// Background: light gray / near-black
<div className="bg-background">...</div>

// Text: dark / light
<p className="text-foreground">...</p>

// Overlay / tinted background
<div className="bg-background-highlight">...</div>

// Manual dark variant via Tailwind
<div className="bg-gray-50 dark:bg-black/10">...</div>
<p className="text-gray-900 dark:text-gray-100">...</p>

---

Theme System (Dynamic Colors)

The app includes a runtime color theme system that lets users (or pages) switch the primary accent color.

Using the Theme

tsx
'use client';
import { useTheme } from '@/app/contexts/ThemeContext';

export default function ThemedCard() {
  const { colorValue, colorPalette, selectedColor, setSelectedColor } = useTheme();

  return (
    <div style={{ borderLeft: `4px solid ${colorValue}` }}>
      <p style={{ color: colorValue }}>Themed accent text</p>
    </div>
  );
}

Available Theme Colors (palette)

ts
// src/app/constants/colors.ts
export const palette = {
  brand:         "#F9C22E",  // Signature yellow (default)
  brandblack:    "#000605",
  brandwhite:    "#FFF1D6",
  electricPurple:"#3500D3",
  neonYellow:    "#FFF700",
  astroblack:    "#3D2D59",
  pinkyblack:    "#6C6BB4",
  starblack:     "#753062",
  pushblack:     "#371B70",
  champion:      "#E7B12E",
  healpurple:    "#884455",
  electricGreen: "#00FF66",
  electricBlue:  "#00FFFF",
  anotherlove:   "#000108",
};

Theme Persistence

The selected theme color is persisted to localStorage under the key unpartySelectedColor automatically.

---

Voice & Microcopy

Pending / Async States

Use "Thinking…", not "Loading…", for any state where the app is waiting on data (fetches, async computation, generation). unparty positions itself around a model that thinks with you (see #dumbai (n) in KeywordsConfig.json) — "Loading" is generic infra-speak, "Thinking" is on-brand and reinforces that positioning at every wait state, however small.

tsx
// Not this
{loading ? 'Loading…' : content}

// This
{loading ? 'Thinking…' : content}

Known spots still saying "Loading..." as of 2026-09 (not yet swept): TheunpartycloudClient.tsx, MusicBanner.tsx.

---

Last updated: 2026-09-05 — See styling-project.md for Tailwind architecture details and src/app/theunpartytemplate/STYLE.md for the iOS design system.