Skip to main content

Overview

The BLACKICE Portal implements a comprehensive theming system using CSS custom properties (CSS variables) with automatic dark mode support based on system preferences. The theme adapts to user’s OS settings while maintaining consistent visual design.

CSS Custom Properties

The theme system is built on CSS variables defined in the :root scope:
index.html:1395-1427
:root {
    --font-family-base: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    --duration-fast: 150ms;
    --duration-normal: 250ms;
    --ease-standard: cubic-bezier(0.16, 1, 0.3, 1);
    --radius-full: 9999px;
    --space-15: 15px;
    --space-24: 24px;

    /* Light Mode Colors */
    --color-background-light: #f8f9fa;
    --color-surface-light: rgba(255, 255, 255, 0.2);
    --color-text-light: #212529;
    --color-text-secondary-light: #6c757d;
    --color-primary-light: #007bff;
    --color-border-light: #dee2e6;

    /* Dark Mode Colors */
    --color-background-dark: #121212;
    --color-surface-dark: #1e1e1e;
    --color-text-dark: #e8e6e3;
    --color-text-secondary-dark: #8b949e;
    --color-primary-dark: #58a6ff;
    --color-border-dark: #30363d;

    /* Default Theme (Light) */
    --color-background: var(--color-background-light);
    --color-surface: var(--color-surface-light);
    --color-text: var(--color-text-light);
    --color-text-secondary: var(--color-text-secondary-light);
    --color-primary: var(--color-primary-light);
    --color-border: var(--color-border-light);
}

Dark Mode Implementation

The portal automatically switches to dark mode using the prefers-color-scheme media query:
index.html:1429-1438
@media (prefers-color-scheme: dark) {
    :root {
        --color-background: var(--color-background-dark);
        --color-surface: var(--color-surface-dark);
        --color-text: var(--color-text-dark);
        --color-text-secondary: var(--color-text-secondary-dark);
        --color-primary: var(--color-primary-dark);
        --color-border: var(--color-border-dark);
    }
}
The theme automatically adapts when users change their system preferences without requiring a page reload.

Color Palette

--color-background-light: #f8f9fa;
--color-surface-light: rgba(255, 255, 255, 0.2);
Light mode features soft grays with high contrast text for optimal readability in bright environments.

Design Tokens

The theme system includes standardized design tokens:

Typography

--font-family-base: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
The font stack includes Inter as primary font with comprehensive system fallbacks for cross-platform consistency.

Animation & Transitions

--duration-fast: 150ms;
--duration-normal: 250ms;
--ease-standard: cubic-bezier(0.16, 1, 0.3, 1);
These tokens ensure consistent animation timing across all interactive elements.

Spacing & Dimensions

--space-15: 15px;
--space-24: 24px;
--radius-full: 9999px;

Applying Theme Variables

Use CSS custom properties throughout your components:
.container {
  background: var(--color-background);
  color: var(--color-text);
}

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
}

Glass Morphism Effects

The portal extensively uses glassmorphism with backdrop filters:
.glass-card {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 20px;
}

/* Dark mode variant */
@media (prefers-color-scheme: dark) {
  .glass-card {
    background: rgba(0, 0, 0, 0.3);
    border-color: rgba(255, 255, 255, 0.1);
  }
}
Glass effects use backdrop-filter for blur and include -webkit- prefix for Safari support.

Component-Specific Theming

The navigation adapts to theme mode:
.logo {
  font-size: 28px;
  font-weight: 800;
  color: var(--color-text);
  text-shadow: 0 2px 4px rgba(255, 255, 255, 0.5);
}

.nav-link {
  color: var(--color-text-secondary);
  transition: color var(--duration-fast);
}

.nav-link:hover {
  color: var(--color-text);
}

Cards & Boxes

Bento grid cards with theme-aware styling:
.box {
  background: var(--color-surface);
  border-radius: 24px;
  padding: 32px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, .08);
  transition: transform .1s ease-out, box-shadow .3s;
}

/* Dark mode specific cards */
.box.dark-variant {
  background: #262626;
  color: #f3f4f6;
  border: 1px solid #404040;
}

Widget Theme System

The BlackICE widget implements its own theming:
portal.js:17-24
this.theme = {
    font: "'Inter Tight', -apple-system, BlinkMacSystemFont, sans-serif",
    glassBg: "rgba(9, 9, 11, 0.95)",
    glassBorder: "rgba(255, 255, 255, 0.08)",
    accent: "#3b82f6",
    textMain: "#ffffff",
    textMuted: "#a1a1aa"
};
These values are injected into widget styles dynamically:
portal.js:79-156
const css = `
.bi-root { 
  font-family: ${this.theme.font};
}

#bi-trigger {
  background: #18181b !important;
  border: 1px solid ${this.theme.glassBorder};
  color: ${this.theme.textMain};
}

#bi-sidebar {
  background: ${this.theme.glassBg};
  backdrop-filter: blur(24px);
  border: 1px solid ${this.theme.glassBorder};
}
`;

Gradient Effects

The theme includes animated gradient buttons:
index.html:154-256
.btn-labs {
    --c-color-1: rgba(255, 163, 26, .7);
    --c-color-2: #1a23ff;
    --c-color-3: #e21bda;
    --c-color-4: rgba(255, 232, 26, .7);
    --c-shadow: rgba(0, 0, 0, .5);
    --c-radial-inner: #1a1a1a;
    --c-radial-outer: #2a2a2a;
    
    background: radial-gradient(
      circle,
      var(--c-radial-inner),
      var(--c-radial-outer) 80%
    );
    box-shadow: 0 0 14px var(--c-shadow);
}
Gradient buttons use CSS custom properties for color animation and include multiple circle elements for parallax effects.

Best Practices

1. Always Use CSS Variables

/* ✅ Good */
.element {
  background: var(--color-background);
  color: var(--color-text);
}

/* ❌ Bad */
.element {
  background: #f8f9fa;
  color: #212529;
}

2. Leverage Inheritance

/* Define once at root level */
.app-container {
  font-family: var(--font-family-base);
  color: var(--color-text);
}

/* Child elements inherit automatically */
.app-container p {
  /* Inherits color from parent */
}

3. Use Semantic Color Names

/* ✅ Good - Semantic */
--color-primary: #007bff;
--color-text: #212529;

/* ❌ Bad - Generic */
--color-blue: #007bff;
--color-dark-gray: #212529;

Testing Theme Modes

To test dark mode without changing system settings:
// Force dark mode in DevTools Console
document.documentElement.style.colorScheme = 'dark';

// Force light mode
document.documentElement.style.colorScheme = 'light';

// Reset to system preference
document.documentElement.style.colorScheme = '';
You can also use browser DevTools to emulate prefers-color-scheme in the Rendering panel.

Accessibility Considerations

Contrast Ratios

The theme ensures WCAG AA compliance:
  • Light mode text: 4.5:1 contrast ratio minimum
  • Dark mode text: 7:1 contrast ratio for enhanced readability
  • Interactive elements: 3:1 minimum for borders and controls

Reduced Motion

Respect user preferences for reduced motion:
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Extending the Theme

To add new theme variables:
:root {
  /* Existing variables */
  
  /* New custom variables */
  --color-success-light: #28a745;
  --color-success-dark: #4ade80;
  --color-success: var(--color-success-light);
  
  --color-danger-light: #dc3545;
  --color-danger-dark: #f87171;
  --color-danger: var(--color-danger-light);
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-success: var(--color-success-dark);
    --color-danger: var(--color-danger-dark);
  }
}
Always define both light and dark variants for new color variables to maintain consistency across themes.

Build docs developers (and LLMs) love