3cosystem
Design System
Single source of truth for designers, engineers, and writers working across R3SET's 10-surface endorsed brand architecture. One identity layer. One codebase. One account.
The Meaning of "3"
R3SET Enterprises is a Delaware B-Corp. The numeral "3" in every surface name carries meaning across three dimensions — and is the visual thread tying the ecosystem together.
Architecture — Endorsed Brand Model
User Journey Pipeline
The "3" Naming Convention
Pattern: [PREFIX]3[SUFFIX] — the "3" replaces a vowel or acts as the word's structural hinge. These rules are non-negotiable.
The "3" is always uppercase in the wordmark
The "3" is always rendered in the surface's --l-primary color — never white, black, or any other color
Surrounding letters are white (dark bg) or near-black #1A1A1A (light bg) — never in the brand color
Sub-labels (.me, .events, EASY) use lighter weight, smaller size, muted color
New surface names must use the "3" pattern
Logo Construction
| Tier | Usage | Size | Construction |
|---|---|---|---|
| Full lockup | Desktop header, splash, marketing | 32px+ | Wordmark + sub-label + tagline |
| Compact | Mobile header, App Switcher | 20–28px | Wordmark only |
| Favicon | Browser tab, PWA icon | 16–32px | Hexagon mark with surface color fill, white "3" |
The Hexagon Mark
- • Always regular (equilateral), never squashed or rotated beyond 30° increments
- • Filled with surface brand color (or R3SET neutral for parent contexts)
- • White "3" inside: Inter 800, centered both axes
- • No stroke or border on the hexagon
All 11 Surface Palettes
Each surface defines tokens mapping to --l-* CSS custom properties. Click any swatch to copy its hex value. Primary colors meet WCAG AA on their dark backgrounds.
--l-primaryHero brand color — buttons, links, the "3"
--l-primary-darkPressed states, dark mode interactive
--l-primary-lightTonal badges, subtle hover backgrounds
--l-primary-glow12% opacity — glassmorphic borders, card glow
--l-surface-darkPage background (dark theme)
--l-surfaceCard/panel background (dark theme)
--l-textPrimary text on dark backgrounds
--l-text-mutedSecondary text, labels, captions
#DE0201hsl(0, 99%, 44%)rgb(222, 2, 1)—linear-gradient(135deg, #E8654A 0%, #F4904A 40%, #F7B85A 80%, #FAD080 100%)Font System
General Sans is the ecosystem default. M3ET uses Cabinet Grotesk + Satoshi for its warm, premium networking personality. All fonts are loaded via Fontshare.
Body, headings, display — all surfaces
Hero headings, display text on M3ET
Body copy on M3ET
Type Scale (Major Third — 1.25×, base 16px)
--fs-xs12pxAaLegal, footnotes, captions--fs-sm13pxAaTimestamps, helper text--fs-base14pxAaBody copy, form labels--fs-md16pxAaDefault body--fs-lg18pxAaLead paragraphs--fs-xl20pxAaSmall headings--fs-2xl24pxAah3--fs-3xl30pxAah2--fs-4xl36pxAah1--fs-5xl48pxAaHero--fs-6xl60pxAaDisplay--fs-7xl72pxAaMarketing hero (desktop)Letter Spacing Rules
| Context | Value | Rule |
|---|---|---|
| Display (≥48px) | -0.02em | Tighten large display text |
| Headings (24–48px) | -0.01em | Slight tightening for hierarchy |
| Body | 0 | Never adjust body copy tracking |
| All-caps labels | +0.06em | Open-track uppercase for legibility |
| Lowercase text | Never adjust | Do not letter-space lowercase — ever |
4px Base Unit
All spacing values are multiples of 4. The grid uses 12 columns on desktop, 8 on tablet, 4 on mobile. Content max-width is 1200px, centered with auto margins.
--space-14pxIcon gap--space-28pxButton icon-label gap--space-416pxInput horizontal padding--space-624pxCard padding, mobile page padding--space-832pxSection separation (small)--space-1248pxDesktop page padding--space-1664pxBetween major sections--space-2080pxHero paddingLayout Grid
| Breakpoint | Columns | Gutter | Max Width |
|---|---|---|---|
| Mobile (< 640px) | 4 | 16px | — |
| Tablet (640–1023px) | 8 | 24px | — |
| Desktop (≥ 1024px) | 12 | 32px | 1200px centered |
Border Radius Tokens
8pxBadges12pxInputs16pxCards24pxFeature cards9999pxPillsUI Components
All components read from --l-* tokens, never hardcoded hex values. Tokens auto-adapt per surface context via data-surface attribute.
Buttons
Cards
Background rgba(255,255,255,0.04) · border rgba(255,255,255,0.08) · backdrop-filter blur(12px)
Surface background · subtle border · layered box-shadow elevation
Badges
Height 24px · padding 0 8px · 12px font · weight 500 · tracking 0.03em · radius 9999px
Input
Avatar
Motion System
All animations use the standard easing curves. Reduced motion must be respected. Never apply scroll-behavior: smooth globally — use it only for programmatic anchor navigation.
Easing Curves
cubic-bezier(0.0, 0.0, 0.2, 1.0)Elements entering (ease-out)
cubic-bezier(0.4, 0.0, 1.0, 1.0)Elements leaving (ease-in)
cubic-bezier(0.4, 0.0, 0.2, 1.0)State changes
cubic-bezier(0.34, 1.56, 0.64, 1.0)Playful emphasis
Duration Scale
| Token | Value | Usage |
|---|---|---|
--dur-feedback | 100ms | Button press, checkbox |
--dur-transition | 200ms | Color changes, hover states |
--dur-entrance | 300ms | Elements animating in |
--dur-complex | 500ms | Multi-step, page transitions |
--dur-slow | 800ms | Large hero animations |
Standard Animations
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeOutDown {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(8px); }
}
@keyframes scaleIn {
from { opacity: 0; transform: scale(0.96); }
to { opacity: 1; transform: scale(1); }
}
/* Stagger: 50ms per item, cap at 200ms for lists > 5 items */
.list-item:nth-child(1) { animation-delay: 0ms; }
.list-item:nth-child(2) { animation-delay: 50ms; }
.list-item:nth-child(3) { animation-delay: 100ms; }
.list-item:nth-child(4) { animation-delay: 150ms; }
.list-item:nth-child(5+) { animation-delay: 200ms; }@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
/* Fade is the only allowed fallback — never skip entirely */
.fade-transition { transition: opacity 150ms ease !important; }
}Writing for the 3cosystem
The parent R3SET voice is confident, warm, cooperative, and direct. Each surface adapts tone while maintaining shared vocabulary and core values.
- • Active voice always — never passive constructions
- • Contractions are fine: "you're", "we're", "it's"
- • Numbers under 10: spell out in body copy (except "3" — always numeral)
- • Use "you" and "your community" — never "users" or "accounts"
Per-Surface Tone
"The right connection changes everything"
"You should own your digital identity"
"Everyone has a story worth telling"
"Success is collective, not competitive"
"Great events need the right people, not top-down organizers"
"Health is a practice, not a destination"
"Every expert was once a beginner"
"Knowledge that compounds"
"Commerce without the middleman"
"Earn by contributing"
WCAG 2.2 AA Minimum
Accessibility is non-negotiable across all surfaces. AAA is the target for body copy. All primary colors meet at minimum AA on their dark backgrounds.
- ·WCAG 2.2 AA minimum for all UI
- ·AAA target for body copy (≥7:1)
- ·All text tokens achieve ≥13:1
- ·Primary colors ≥4.5:1 on dark bg
- ·44×44px minimum on all interactive elements
- ·Buttons: min height 44px (md size = 40px, use lg)
- ·Nav items: min 44px hit area
- ·Icon buttons: pad to 44px even if icon is 20px
- ·outline: 2px solid var(--l-primary)
- ·outline-offset: 2px
- ·:focus-visible only — not :focus
- ·Never remove focus rings; restyle if needed
- ·All animations have prefers-reduced-motion fallback
- ·Fallback: opacity fade — never skip entirely
- ·Test with OS reduced motion setting
- ·animation-duration: 0.01ms !important
- ·Never convey info through color alone
- ·Always add icon + text alongside color
- ·Error states: icon + color + text message
- ·Status badges: label + color, never color alone
- ·alt text on all meaningful images
- ·aria-label on icon-only buttons
- ·aria-live on dynamic status messages
- ·Logical heading hierarchy (h1→h2→h3)
Non-Negotiable Consistency
These 11 rules apply to every surface without exception. They ensure the 3cosystem feels cohesive even as individual surfaces express distinct personalities.
In every wordmark, always --l-primary. Never white, black, or any other color.
Every surface, links to TeamR3SET.com. The "3" in #DE0201.
Accessible from every surface (top-right icon or sidebar menu).
One Supabase Auth instance. One account, one session, everywhere.
"One R3SET account for everything" — always on login pages.
32×32px, surface color fill, white "3". Generated for 16, 32, 180, 192, 512px.
In-app respects prefers-color-scheme, but landing pages always default dark.
max-width: 1200px; margin: 0 auto; on all content containers. No raw full-width content.
scroll-behavior: smooth is never global. Use scrollIntoView({ behavior: 'smooth' }) only for programmatic anchor nav.
No text on screen renders below 12px. This is the absolute floor.
Answer "what is the one thing this page must communicate?" before designing. Build that element first.
Dark / Light Theme System
Dark mode is the default for landing and login pages. In-app respects prefers-color-scheme. The lightness inversion formula generates light-mode starting points from any dark token.
CSS Token Structure
[data-surface="surface-id"] {
--l-primary: #XXXXXX;
--l-primary-dark: #XXXXXX;
--l-primary-light: #XXXXXX;
--l-primary-glow: rgba(R,G,B, 0.12);
--l-surface-dark: #XXXXXX; /* Page bg */
--l-surface: #XXXXXX; /* Card bg */
--l-surface-2: #XXXXXX; /* Nested */
--l-border: #XXXXXX;
--l-text: #XXXXXX;
--l-text-muted: #XXXXXX;
/* Semantic (derived) */
--l-focus-ring: var(--l-primary);
--l-btn-primary-bg: var(--l-primary);
}Dark/Light Toggle Hook
function useTheme() {
const [theme, setTheme] = useState(
() => localStorage.getItem('r3set-theme')
?? (window.matchMedia(
'(prefers-color-scheme: dark)'
).matches ? 'dark' : 'light')
);
useEffect(() => {
document.documentElement
.setAttribute('data-theme', theme);
localStorage.setItem('r3set-theme', theme);
}, [theme]);
return {
theme,
toggleTheme: () =>
setTheme(t => t === 'dark' ? 'light' : 'dark')
};
}Lightness Inversion Formula
To generate a light theme starting point: convert to HSL, subtract L from 100, adjust by eye.
| Token | Dark L | → Light L (100-x) | Adjusted value |
|---|---|---|---|
| surface-dark | 6% | 94% | #FFFFFF (100%) |
| surface | 9% | 91% | #F8F8FA (97%) |
| text | 94% | 6% | #1A1A2E (14%) |
| text-muted | 57% | 43% | #6B6B80 (46%) |
[data-theme="light"] {
--l-surface-dark: #FFFFFF; /* hsl(0, 0%, 100%) */
--l-surface: #F8F8FA; /* hsl(240, 11%, 97%) */
--l-surface-2: #F0F0F5; /* hsl(240, 14%, 95%) */
--l-border: rgba(0, 0, 0, 0.08);
--l-text: #1A1A2E; /* hsl(240, 27%, 14%) */
--l-text-muted: #6B6B80; /* hsl(240, 9%, 46%) */
/* Primary colors are UNCHANGED across themes */
}Dark Theme Layering
--l-surface-dark#0E0F12--l-surface#15161A--l-surface-2#1C1D24rgba(0,0,0,0.7)overlayGlobal Fallback (No Surface Context)
:root {
--l-primary: #DE0201;
--l-primary-dark: #B50100;
--l-primary-light: #FF6B6A;
--l-primary-glow: rgba(222, 2, 1, 0.12);
--l-surface-dark: #0E0F12;
--l-surface: #15161A;
--l-surface-2: #1C1D24;
--l-border: #2A2B36;
--l-text: #EDEDF0;
--l-text-muted: #8B8C99;
}