Skip to main content
200 Mates uses a custom CSS architecture built around CSS custom properties (variables) and a carefully crafted dark theme optimized for the globe visualization.

Single Stylesheet Approach

All styles are contained in a single file: styles/style.css (805 lines) Benefits:
  • No build process or CSS preprocessing
  • Easy to locate and modify styles
  • Fast loading with a single HTTP request
  • Clear cascade and specificity
The stylesheet is loaded in the <head> of index.html:16 for optimal rendering performance.

CSS Custom Properties

The design system uses CSS variables defined in :root for consistent theming:

Color Palette

style.css
:root {
  /* Primary green (mate/yerba inspired) */
  --verde:        #3d5c35;
  --verde-light:  #5a7d52;
  --verde-dark:   #283d22;
  --verde-glow:   rgba(61, 92, 53, 0.35);
  
  /* Accent colors */
  --yerba:        #7a9e52;  /* Bright green for highlights */
  --tierra:       #b8945e;  /* Earth tone for warnings */
  --tierra-light: #d8c5a0;
  --parchment:    #f0e8d8;  /* Light accent */
  
  /* Dark theme grays */
  --dark:         #0e100c;  /* Body background */
  --dark-2:       #131510;
  --dark-3:       #1a1e14;  /* Card backgrounds */
  --dark-4:       #1f2419;
  --mid:          #2e332a;
  
  /* Text hierarchy */
  --text:         #e2ddd3;  /* Primary text */
  --text-muted:   #7a7868;  /* Secondary text */
  --text-faint:   #484840;  /* Tertiary text */
  
  /* Borders */
  --border:       rgba(120, 158, 82, 0.18);  /* Green tinted */
  --border-warm:  rgba(184, 148, 94, 0.22);  /* Warm tinted */
}

Layout Variables

:root {
  --radius:     8px;   /* Standard border radius */
  --radius-lg:  14px;  /* Large border radius */
  --font:       'DM Sans', sans-serif;
}
The green color palette is inspired by mate (yerba mate), creating a cohesive visual connection between the UI and the subject matter.

Typography

Font Family

The entire application uses DM Sans, loaded from Google Fonts:
index.html
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&display=swap" rel="stylesheet">
Weights used:
  • 300 (Light) - Sparingly for subtle elements
  • 400 (Regular) - Body text
  • 500 (Medium) - Secondary headings
  • 600 (Semi-bold) - Labels and buttons
  • 700 (Bold) - Primary headings and emphasis

Type Scale

h1 { font-size: 24px; font-weight: 700; }  /* Header title */

.panel-title { font-size: 16px; font-weight: 700; }  /* Section headings */

.gallery-name { font-size: 16px; font-weight: 600; }  /* Gallery cards */

body { font-size: 13px; }  /* Base font size */

.field-label { font-size: 12px; font-weight: 600; }  /* Form labels */

.drop-content p { font-size: 11px; }  /* Menu text */

.hstat-label { font-size: 11px; }  /* Stat labels */
Font sizes are deliberately small (13px base) to maximize information density while maintaining readability on the compact side panel.

Component Styles

Header (style.css:47-93)

.site-header {
  position: sticky;
  top: 0;
  z-index: 500;
  background: rgba(12, 13, 10, 0.97);
  backdrop-filter: blur(20px);  /* Frosted glass effect */
  border-bottom: 1px solid var(--border);
  padding: 0 24px;
}
Features:
  • Sticky positioning keeps header visible while scrolling
  • Backdrop blur creates depth
  • Semi-transparent background

Globe Section (style.css:280-301)

.globe-section {
  flex: 1;
  background: radial-gradient(
    ellipse at 50% 50%, 
    #111608 0%, 
    #080908 100%
  );
}
The background gradient creates a subtle vignette effect that draws attention to the center of the globe.

Side Panel (style.css:303-320)

.side-panel {
  width: 340px;
  height: 100%;
  overflow-y: auto;
  background: #131510;
  border-left: 1px solid rgba(122,158,82,.12);
  /* Custom scrollbar */
  scrollbar-width: thin;
  scrollbar-color: var(--mid) transparent;
}
Fixed width ensures consistent layout across screen sizes (until mobile breakpoint).

Form Inputs (style.css:422-435)

.field-input {
  background: var(--dark-3);
  border: 1px solid rgba(122,158,82,.18);
  border-radius: 7px;
  color: var(--text);
  padding: 10px 12px;
  transition: border-color .18s, box-shadow .18s;
}

.field-input:focus {
  border-color: rgba(122,158,82,.45);
  box-shadow: 0 0 0 2px rgba(61,92,53,.2);  /* Glow effect */
}
Accessibility: Focus states are prominent with both color and shadow changes.

Buttons (style.css:480-498)

.btn-submit-main {
  background: var(--verde);
  border: none;
  border-radius: 8px;
  color: #fff;
  padding: 14px;
  font-size: 17px;
  font-weight: 600;
  box-shadow: 0 3px 16px rgba(61,92,53,.3);
  transition: background .2s, transform .15s, box-shadow .2s;
}

.btn-submit-main:hover:not(:disabled) {
  background: var(--verde-light);
  transform: translateY(-1px);  /* Lift effect */
  box-shadow: 0 5px 22px rgba(61,92,53,.42);
}
Micro-interactions: Buttons lift on hover for tactile feedback.
.gallery-card {
  display: flex;
  align-items: center;
  gap: 14px;
  background: #1a1e14;
  border: 1px solid rgba(122,158,82,.14);
  border-radius: 8px;
  padding: 10px 12px;
  animation: cardIn .35s ease both;
}

@keyframes cardIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
Staggered animation creates a pleasant reveal effect when cards load.

Dark Theme for Globe

The color scheme is specifically optimized for the dark globe background:
  • Dark backgrounds (--dark, --dark-2, --dark-3) prevent UI from competing with the globe
  • Green accents (--yerba, --verde) complement the earth tones of the globe
  • Subtle borders use low opacity to avoid harsh edges
  • Warm accents (--tierra) provide contrast for warnings and secondary actions

Visual Effects

Noise Texture

style.css:40-45
body::before {
  content: '';
  position: fixed;
  inset: 0;
  background-image: url("data:image/svg+xml,..fractalNoise..");
  pointer-events: none;
  opacity: 0.4;
}
A subtle fractal noise overlay adds texture and depth to the entire interface.

Backdrop Blur

Used throughout for depth and layering:
.site-header { backdrop-filter: blur(20px); }
.drop-backdrop { backdrop-filter: blur(3px); }
.lightbox-bg { backdrop-filter: blur(8px); }

Shadows

Shadows create hierarchy and elevation:
/* Subtle elevation */
box-shadow: 0 3px 16px rgba(61,92,53,.3);

/* Prominent modals */
box-shadow: 0 20px 60px rgba(0,0,0,.95);

/* Glow effects */
box-shadow: 0 0 14px rgba(122,158,82,.3);

Animations

Success Modal (style.css:617-710)

Elaborate animation sequence:
.smodal-mate-emoji {
  animation: mateWobble .6s ease .1s both;
}

@keyframes mateWobble {
  0%   { transform: scale(.5) rotate(-8deg); opacity: 0; }
  60%  { transform: scale(1.1) rotate(3deg); opacity: 1; }
  80%  { transform: scale(.95) rotate(-1deg); }
  100% { transform: scale(1) rotate(0deg); }
}
Sequenced animations:
  1. Mate emoji wobbles in
  2. Title fades up (.2s delay)
  3. Body text fades up (.28s delay)
  4. Divider fades up (.32s delay)
  5. Button fades up (.42s delay)

Hamburger Icon (style.css:96-124)

.ham-btn.is-open .ham-bar:nth-child(1) {
  transform: translateY(8px) rotate(45deg);
}
.ham-btn.is-open .ham-bar:nth-child(2) {
  opacity: 0;
  transform: scaleX(0);
}
.ham-btn.is-open .ham-bar:nth-child(3) {
  transform: translateY(-8px) rotate(-45deg);
}
Classic three-bar to X transformation.

Responsive Design

Mobile Breakpoint (style.css:714-736)

@media (max-width: 768px) {
  .main-layout {
    flex-direction: column;  /* Stack vertically */
    height: auto;
  }
  
  .globe-section {
    height: 55vw;  /* Proportional height */
    min-height: 260px;
    max-height: 380px;
  }
  
  .side-panel {
    width: 100%;  /* Full width */
    border-left: none;
    border-top: 1px solid var(--border);
  }
  
  .header-stats { display: none; }  /* Hide stats on small screens */
}

Small Mobile (style.css:774-778)

@media (max-width: 380px) {
  h1 { font-size: 13px; }
  .emoji-big { font-size: 22px; }
  .lang-btn { font-size: 10px; padding: 2px 4px; }
}

Customization Tips

1

Change the color scheme

Modify the CSS custom properties in :root (lines 5-26):
:root {
  --verde: #your-color;
  --yerba: #your-accent;
}
All components will automatically update.
2

Adjust spacing

Update padding and gap values in component classes:
.side-panel { width: 400px; }  /* Wider panel */
.panel-block { padding: 24px; }  /* More breathing room */
3

Modify animations

Change animation durations and easing:
.gallery-card {
  animation: cardIn .5s cubic-bezier(.34,1.4,.64,1) both;
}
4

Add a light theme

Create a class or media query with updated custom properties:
@media (prefers-color-scheme: light) {
  :root {
    --dark: #ffffff;
    --text: #1a1e14;
    /* ... */
  }
}
Be careful when changing the dark theme colors - the globe visualization is optimized for dark backgrounds. A light theme would require significant adjustments to the globe rendering code in modules/globe.js.

Next: Deployment

Learn how to deploy 200 Mates to production.

Build docs developers (and LLMs) love