-
Notifications
You must be signed in to change notification settings - Fork 0
UI Design System
Color values confirmed against app/globals.css at time of writing.
Felines uses an editorial design system with alternating light and dark sections, Inter typography, a palette derived from the logo cat, and subtle animations that make the product feel alive without being distracting.
See Visual Identity for the full palette table — implemented as CSS custom properties in app/globals.css's @theme block (Tailwind v4, no JS config file).
| Variant | Background | Text | Border | Use |
|---|---|---|---|---|
| Primary | #B66119 |
#FFFFFF |
— | Main action |
| Secondary | transparent | #B66119 |
1.5px #B66119
|
Secondary action |
| Ghost | transparent | #6B6B6B |
1px #E8E4DF
|
Tertiary actions |
| Danger | #C0392B |
#FFFFFF |
— | Destructive actions |
| White | #FFFFFF |
#2D1810 |
— | On dark sections |
Border radius 10px, padding 12px 24px, hover translateY(-1px) + subtle shadow, press scale(0.97).
Background #FFFFFF, 1px #E8E4DF border, 16px radius, 24px padding, 0 2px 8px rgba(0,0,0,0.05) shadow. Hover: translateY(-3px) + larger shadow.
48px height, 1px #E8E4DF border, 8px radius. Focus: border #B66119, 2px rgba(182,97,25,0.2) outline.
Pill shape (20px radius), 4px 12px padding, 12px semibold. Neutered: golden bg. Verified: success bg. Read: neutral bg. Emergency: emergency bg/white text.
rgba(0,0,0,0.5) backdrop with 4px blur, 20px radius container, 32px padding, max-width 560px, slide-up animation (250ms cubic-bezier(0.16, 1, 0.3, 1)). Focus is trapped and Escape closes — implemented via a shared hook reused across all modals after 15 were found missing it during the WCAG audit.
Active: 2px #B66119 underline, #B66119 text. Inactive: #6B6B6B text. The underline slides horizontally between tabs (200ms ease).
All respect prefers-reduced-motion.
Page load fade-up: staggered — hero 0ms, subheadline 100ms, CTAs 200ms.
Scroll reveal: Intersection Observer (not a scroll listener), fade + translateY(16px→0), 400ms ease-out, 80ms stagger between items.
Count-up: numbers on /impact and home count from 0 to their final value via requestAnimationFrame, 800ms ease-out, triggered by Intersection Observer.
Map pin hover: spring scale 1→1.3x with overshoot, cubic-bezier(0.34, 1.56, 0.64, 1). Emergency pins pulse with a 2s infinite ripple.
Skeletons: shimmer keyframe animation for loading states.
Grid: desktop max-width 1200px with 48px horizontal padding; mobile 20px horizontal padding. Sections use 80px vertical padding (desktop), 60px (mobile).
Visual rhythm: alternating light/dark sections create editorial pacing — hero (light) → stats strip (dark) → entry cards (light) → cat assistant video (light) → quick facts (dark) → final CTA (light).
| Criterion | Implementation |
|---|---|
| Normal text contrast | Minimum 4.5:1 — verified and corrected (a success-state color was 3.3:1) |
| Large text contrast | Minimum 3:1 — verified |
| Focus ring | 2px #B66119 (light backgrounds), 2px #F2AE72 (dark backgrounds) |
| Modal focus trap | Shared hook — 15 modals fixed |
| ARIA roles | Tabs, modals, progress bars, dropdowns |
aria-live |
Notifications, confirmations, report counters |
| Alt text | All colony and cat images |
| Labels | Every input has a real <label>, not just a placeholder (2 forms fixed) |
| Touch targets | Minimum 44×44px on every interactive element |
lang attribute |
Updated dynamically with the PT/EN toggle |
| Reduced motion | All animations disabled via media query |
- No purely decorative elements — everything exists for a functional reason
- Empty states as an invitation — never an error, always with a CTA
- Hierarchy through size, not color — structure stays clear without depending on color alone
- Immediate feedback — every action gets a visual response in under 200ms
- Mobile first — every component is designed for 375px before desktop