|$ curl https://forge-ai.dev/api/markdown?path=docs/css/dark-mode
$cat docs/css-—-dark-mode-&-theme-switching.md
updated Recently·25 min read·published

CSS — Dark Mode & Theme Switching

CSSDark ModeThemingCSS VariablesIntermediate🎯Free Tools
Introduction

Dark mode has evolved from a niche preference to a fundamental feature of modern interfaces. It reduces eye strain in low-light environments, saves battery life on OLED displays, and satisfies the explicit prefers-color-schemepreference that over half of desktop users enable. A well-implemented theme system doesn't just flip colors — it requires a coherent token-based architecture that keeps every component in sync across themes.

There are three primary approaches to implementing dark mode in CSS: a pure CSS media query that automatically follows the OS setting, a JavaScript toggle that writes a class or attribute to the document root, and a hybrid approach that respects system preference while allowing manual override. All three rely on the same foundation — CSS custom properties — to swap color tokens at scale.

This guide walks through each approach with production-ready code, covering token architecture, FOUC prevention, multi-theme systems, image handling, accessibility, and transition animations. Every example uses semantic naming so your color system stays maintainable as the design evolves.

dark-mode-pillars.css
CSS
1/* The three pillars of dark mode */
2/* 1. System preference detection */
3@media (prefers-color-scheme: dark) {
4 :root { --bg: #0D0D0D; --text: #E0E0E0; }
5}
6
7/* 2. Class-based toggle */
8.dark {
9 --bg: #0D0D0D;
10 --text: #E0E0E0;
11}
12
13/* 3. Data attribute (multi-theme) */
14[data-theme="dark"] {
15 --bg: #0D0D0D;
16 --text: #E0E0E0;
17}
CSS Custom Properties for Theming

CSS custom properties are the backbone of any theme system. Define every color, shadow, border, and spacing value as a token in :root, then override them under your theme selector. Components never reference raw hex values — they always consume tokens, making theme switching a single reassignment at the root level.

Name tokens semantically by purpose, not by color. --color-surface communicates intent; --color-white couples the token to a specific value. Semantic tokens also let you adjust contrast per theme — a color that passes AA on dark backgrounds may fail on light ones, so you swap the entire value rather than patching individual declarations.

light-tokens.css
CSS
1:root {
2 /* Surface colors */
3 --color-bg-primary: #FFFFFF;
4 --color-bg-secondary: #F5F5F5;
5 --color-bg-tertiary: #E5E5E5;
6 --color-bg-elevated: #FFFFFF;
7
8 /* Text colors */
9 --color-text-primary: #0D0D0D;
10 --color-text-secondary: #525252;
11 --color-text-muted: #808080;
12 --color-text-inverse: #FFFFFF;
13
14 /* Accent colors */
15 --color-accent: #00FF41;
16 --color-accent-hover: #00CC34;
17 --color-accent-muted: rgba(0, 255, 65, 0.1);
18
19 /* Semantic colors */
20 --color-success: #22C55E;
21 --color-warning: #FFB000;
22 --color-error: #EF4444;
23 --color-info: #3B82F6;
24
25 /* Border & shadow */
26 --color-border: #E5E5E5;
27 --color-border-subtle: #F0F0F0;
28 --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
29 --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
30 --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.12);
31}
preview
System Preference Detection

The prefers-color-scheme media query detects the user's operating system theme preference. It returns dark when the OS is set to dark mode, light for light mode, and can also match no-preference when the OS has no explicit setting. This is the zero-JavaScript path to dark mode.

Define light theme values in :root (the default) and override them under @media (prefers-color-scheme: dark). This approach requires no JavaScript and respects the user's system-wide choice — but it doesn't allow in-page toggling.

system-preference.css
CSS
1:root {
2 --bg: #FFFFFF;
3 --text: #0D0D0D;
4 --surface: #F5F5F5;
5 --border: #E5E5E5;
6 --accent: #00FF41;
7 --muted: #808080;
8}
9
10@media (prefers-color-scheme: dark) {
11 :root {
12 --bg: #0D0D0D;
13 --text: #E0E0E0;
14 --surface: #1A1A1A;
15 --border: #222222;
16 --accent: #00FF41;
17 --muted: #525252;
18 }
19}
20
21/* Also handle no-preference */
22@media (prefers-color-scheme: no-preference) {
23 :root {
24 /* Default to dark for users who haven't chosen */
25 --bg: #0D0D0D;
26 --text: #E0E0E0;
27 }
28}
29
30body {
31 background: var(--bg);
32 color: var(--text);
33 font-family: system-ui;
34 transition: background-color 0.3s, color 0.3s;
35}
📝

note

When to respect system preference vs. user choice: If your site has a manual theme toggle, the toggle should win. Store the user's explicit choice and only fall back to the system preference when no stored choice exists. This gives the best of both worlds — automatic behavior for new visitors, respect for returning users' preferences.
Class-Based Dark Mode

The most flexible approach is toggling a .dark class on the <html> element. All dark mode overrides live under a single .dark selector, and JavaScript adds or removes the class based on user preference. This pattern integrates with localStorage for persistence and matchMedia for system detection.

The key advantage of class-based theming is granular control: you can combine it with prefers-color-scheme for a default, then let the class override. This also supports scoped themes — apply .dark to a specific container instead of the root for embedded dark panels.

class-based-dark.css
CSS
1:root {
2 --bg-primary: #FFFFFF;
3 --bg-secondary: #F5F5F5;
4 --bg-surface: #FAFAFA;
5 --text-primary: #0D0D0D;
6 --text-secondary: #525252;
7 --text-muted: #808080;
8 --accent: #00FF41;
9 --accent-hover: #00CC34;
10 --border: #E5E5E5;
11 --shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
12}
13
14.dark {
15 --bg-primary: #0D0D0D;
16 --bg-secondary: #1A1A1A;
17 --bg-surface: #141414;
18 --text-primary: #E0E0E0;
19 --text-secondary: #A0A0A0;
20 --text-muted: #525252;
21 --accent: #00FF41;
22 --accent-hover: #33FF66;
23 --border: #222222;
24 --shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
25}
26
27body {
28 background-color: var(--bg-primary);
29 color: var(--text-primary);
30 transition: background-color 0.3s ease, color 0.3s ease;
31}
preview
JavaScript Theme Toggle

A production theme manager needs to solve three problems: persist the user's choice across page loads, detect the system preference as a default, and prevent flash of wrong theme (FOUC) during the initial paint. The script below handles all three by executing synchronously in the <head> before any content renders.

The theme manager reads localStorage for an explicit user choice. If none exists, it checks the system preference via matchMedia. The class is applied to <html> immediately — before CSS parses — eliminating any flash. A <script> tag in <head> with this code is the standard pattern.

theme-manager.js
JavaScript
1// Inline in <head> to prevent FOUC
2(function() {
3 const stored = localStorage.getItem('theme');
4 const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
5 const theme = stored || (prefersDark ? 'dark' : 'light');
6 document.documentElement.classList.add(theme);
7 document.documentElement.setAttribute('data-theme', theme);
8})();
9
10// Theme toggle function
11function toggleTheme() {
12 const html = document.documentElement;
13 const current = html.classList.contains('dark') ? 'dark' : 'light';
14 const next = current === 'dark' ? 'light' : 'dark';
15
16 html.classList.remove(current);
17 html.classList.add(next);
18 html.setAttribute('data-theme', next);
19 localStorage.setItem('theme', next);
20
21 // Update toggle button icon
22 const btn = document.querySelector('[data-theme-toggle]');
23 if (btn) btn.textContent = next === 'dark' ? '\u2600' : '\u263E';
24}
25
26// Listen for system theme changes
27window.matchMedia('(prefers-color-scheme: dark)')
28 .addEventListener('change', (e) => {
29 if (!localStorage.getItem('theme')) {
30 const theme = e.matches ? 'dark' : 'light';
31 document.documentElement.classList.add(theme);
32 document.documentElement.setAttribute('data-theme', theme);
33 }
34 });

warning

The inline script that sets the initial class MUST run in <head> before any visible content. If it runs in the body or is deferred, the browser will briefly render light-mode styles before the class is applied, creating a visible flash. Place it as the first script tag in your document head.
Flash of Unstyled Content (FOUC)

FOUC occurs when the browser renders content before the correct theme is applied. On a page with dark mode, users might see a brief white flash before the dark theme loads. The fix is a synchronous inline script that runs before the browser paints. You can also add a CSS rule that defaults to the most common theme.

fouc-prevention.html
HTML
1<!-- Option 1: Inline script in <head> (recommended) -->
2<head>
3 <script>
4 (function() {
5 var t = localStorage.getItem('theme')
6 || (matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light');
7 document.documentElement.classList.add(t);
8 })();
9 </script>
10 <link rel="stylesheet" href="/styles.css" />
11</head>
12
13<!-- Option 2: CSS-only default (less flexible) -->
14<style>
15 :root { color-scheme: light; }
16 .dark { color-scheme: dark; }
17</style>
18
19<!-- Option 3: Meta tag color-scheme -->
20<head>
21 <meta name="color-scheme" content="light dark" />
22</head>

info

Add color-scheme: light dark to your :root CSS. This tells the browser which color schemes your page supports, allowing it to correctly render browser chrome (scrollbars, form controls) in the matching scheme — even before your JavaScript runs.
Complete Theme System

A production-ready theme system goes beyond swapping background and text colors. It covers shadows, borders, gradients, focus rings, scrollbars, form controls, and every interactive state. The full token set below provides semantic naming, WCAG AA contrast ratios, and theme-aware states for hover, active, focus, and disabled.

complete-theme.css
CSS
1:root {
2 color-scheme: light dark;
3
4 /* Backgrounds */
5 --bg-base: #FFFFFF;
6 --bg-surface: #F9FAFB;
7 --bg-elevated: #FFFFFF;
8 --bg-overlay: rgba(0, 0, 0, 0.5);
9 --bg-muted: #F3F4F6;
10
11 /* Text */
12 --text-base: #111827;
13 --text-secondary: #6B7280;
14 --text-muted: #9CA3AF;
15 --text-inverse: #FFFFFF;
16 --text-accent: #059669;
17
18 /* Interactive */
19 --accent-base: #059669;
20 --accent-hover: #047857;
21 --accent-active: #065F46;
22 --accent-subtle: rgba(5, 150, 105, 0.1);
23 --accent-focus-ring: rgba(5, 150, 105, 0.4);
24
25 /* Borders */
26 --border-default: #E5E7EB;
27 --border-strong: #D1D5DB;
28 --border-subtle: #F3F4F6;
29
30 /* Shadows */
31 --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
32 --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
33 --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.1);
34 --shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.06);
35
36 /* Semantic */
37 --success: #16A34A;
38 --warning: #D97706;
39 --error: #DC2626;
40 --info: #2563EB;
41
42 /* Focus */
43 --focus-ring: 0 0 0 3px var(--accent-focus-ring);
44
45 /* Radius */
46 --radius-sm: 6px;
47 --radius-md: 8px;
48 --radius-lg: 12px;
49 --radius-full: 9999px;
50
51 /* Transitions */
52 --transition-fast: 150ms ease;
53 --transition-normal: 250ms ease;
54 --transition-slow: 400ms ease;
55}
56
57.dark {
58 --bg-base: #0A0A0A;
59 --bg-surface: #141414;
60 --bg-elevated: #1C1C1C;
61 --bg-overlay: rgba(0, 0, 0, 0.7);
62 --bg-muted: #1C1C1C;
63
64 --text-base: #F3F4F6;
65 --text-secondary: #9CA3AF;
66 --text-muted: #6B7280;
67 --text-inverse: #111827;
68 --text-accent: #34D399;
69
70 --accent-base: #34D399;
71 --accent-hover: #6EE7B7;
72 --accent-active: #A7F3D0;
73 --accent-subtle: rgba(52, 211, 153, 0.1);
74 --accent-focus-ring: rgba(52, 211, 153, 0.3);
75
76 --border-default: #262626;
77 --border-strong: #333333;
78 --border-subtle: #1F1F1F;
79
80 --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
81 --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
82 --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.5);
83 --shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.3);
84
85 --success: #4ADE80;
86 --warning: #FBBF24;
87 --error: #F87171;
88 --info: #60A5FA;
89
90 --focus-ring: 0 0 0 3px var(--accent-focus-ring);
91}
92
93/* Apply tokens */
94body {
95 background-color: var(--bg-base);
96 color: var(--text-base);
97 transition: background-color var(--transition-normal), color var(--transition-normal);
98}
99
100a { color: var(--text-accent); }
101a:hover { color: var(--accent-hover); }
102:focus-visible { outline: none; box-shadow: var(--focus-ring); }
preview

best practice

Use semantic token names (--text-base, --bg-surface) rather than literal color names (--gray-900). Semantic names communicate intent and survive palette changes. When a designer says "make the card background darker," you update one token instead of hunting through every component.
Accessibility & Contrast Ratios

WCAG 2.1 requires a minimum contrast ratio of 4.5:1 for normal text (AA) and 3:1 for large text. AAA requires 7:1 for normal text. Dark mode often fails these thresholds because light-on-dark combinations that look vibrant to developers with good vision may be unreadable for users with low vision or color blindness.

Test every theme independently with a contrast checker. The --text-secondary token must hit 4.5:1 against both --bg-base in light mode and dark mode. Focus indicators are also frequently neglected — a :focus-visible ring that looks great on light backgrounds may disappear on dark surfaces.

accessibility.css
CSS
1/* Focus ring that works in both themes */
2:focus-visible {
3 outline: none;
4 box-shadow: 0 0 0 2px var(--bg-base), 0 0 0 4px var(--accent-base);
5}
6
7/* High-contrast focus for dark mode */
8.dark :focus-visible {
9 box-shadow: 0 0 0 2px var(--bg-base), 0 0 0 4px var(--accent-base);
10}
11
12/* Skip-to-content link */
13.skip-link {
14 position: absolute;
15 top: -100%;
16 left: 16px;
17 padding: 8px 16px;
18 background: var(--accent-base);
19 color: var(--text-inverse);
20 border-radius: var(--radius-md);
21 font-weight: 600;
22 z-index: 100;
23}
24
25.skip-link:focus {
26 top: 16px;
27}
28
29/* Reduced motion: disable transitions */
30@media (prefers-reduced-motion: reduce) {
31 *, *::before, *::after {
32 transition-duration: 0.01ms !important;
33 animation-duration: 0.01ms !important;
34 }
35}
36
37/* High contrast mode support */
38@media (forced-colors: active) {
39 .btn {
40 border: 1px solid ButtonText;
41 background: ButtonFace;
42 color: ButtonText;
43 }
44}

warning

Never use color alone to convey information. A red badge and a green badge look identical to users with deuteranopia. Always pair color with text, icons, or patterns. This applies equally to both light and dark themes.
Advanced: Multiple Themes

Beyond light and dark, many applications benefit from additional themes: sepia for reading, high-contrast for accessibility, solarized for reduced blue light, or fully custom brand themes. The data-theme attribute approach scales cleanly — each theme is a separate selector block that overrides the same set of tokens.

multi-theme.css
CSS
1/* Sepia theme */
2[data-theme="sepia"] {
3 --bg-base: #F4ECD8;
4 --bg-surface: #EDE3CC;
5 --text-base: #433422;
6 --text-secondary: #6B5744;
7 --accent-base: #B8860B;
8 --accent-hover: #996B09;
9 --border-default: #D4C4A8;
10}
11
12/* High-contrast theme */
13[data-theme="contrast"] {
14 --bg-base: #000000;
15 --bg-surface: #0A0A0A;
16 --text-base: #FFFFFF;
17 --text-secondary: #E0E0E0;
18 --accent-base: #FFD700;
19 --accent-hover: #FFEC80;
20 --border-default: #FFFFFF;
21 --shadow-md: none;
22}
23
24/* Dracula-inspired */
25[data-theme="dracula"] {
26 --bg-base: #282A36;
27 --bg-surface: #343746;
28 --bg-elevated: #44475A;
29 --text-base: #F8F8F2;
30 --text-secondary: #BFBFBF;
31 --accent-base: #50FA7B;
32 --accent-hover: #69FF94;
33 --border-default: #44475A;
34}
35
36/* Nord */
37[data-theme="nord"] {
38 --bg-base: #2E3440;
39 --bg-surface: #3B4252;
40 --bg-elevated: #434C5E;
41 --text-base: #ECEFF4;
42 --text-secondary: #D8DEE9;
43 --accent-base: #88C0D0;
44 --accent-hover: #8FBCBB;
45 --border-default: #4C566A;
46}
47
48/* Tokyo Night */
49[data-theme="tokyo"] {
50 --bg-base: #1A1B26;
51 --bg-surface: #24283B;
52 --bg-elevated: #414868;
53 --text-base: #C0CAF5;
54 --text-secondary: #9AA5CE;
55 --accent-base: #7AA2F7;
56 --accent-hover: #89B4FA;
57 --border-default: #3B4261;
58}
preview
Transitions & Animations

Smooth theme transitions make the switch feel polished. Apply a transition to the body element that covers background-color and color. For individual components, transition border-color, box-shadow, and any other properties that change between themes.

Respect prefers-reduced-motion by disabling theme transitions for users who have requested reduced animation. The color-scheme property also tells the browser to transition its own UI elements (scrollbars, form controls) when the theme changes.

theme-transitions.css
CSS
1/* Global theme transition */
2body,
3body * {
4 transition:
5 background-color 0.3s ease,
6 color 0.3s ease,
7 border-color 0.3s ease,
8 box-shadow 0.3s ease;
9}
10
11/* But disable for elements that shouldn't animate */
12.no-transition,
13.no-transition * {
14 transition: none !important;
15}
16
17/* Respect reduced motion preference */
18@media (prefers-reduced-motion: reduce) {
19 body,
20 body * {
21 transition: none !important;
22 }
23}
24
25/* Color scheme for browser UI */
26:root {
27 color-scheme: light dark;
28}
29
30/* Scrollbar theming */
31::-webkit-scrollbar {
32 width: 8px;
33}
34
35::-webkit-scrollbar-track {
36 background: var(--bg-surface);
37}
38
39::-webkit-scrollbar-thumb {
40 background: var(--border-default);
41 border-radius: 4px;
42}
43
44::-webkit-scrollbar-thumb:hover {
45 background: var(--border-strong);
46}
47
48/* Form control theming */
49input, textarea, select {
50 background-color: var(--bg-base);
51 color: var(--text-base);
52 border: 1px solid var(--border-default);
53 color-scheme: light dark;
54}
55
56.dark input, .dark textarea, .dark select {
57 color-scheme: dark;
58}
🔥

pro tip

A common mistake is applying the transition to the root element with * selector, which causes FOUC on page load as every element transitions from unstyled to styled. Wrap the transition in a class like .theme-ready that you add via JavaScript after the initial paint.
Images in Dark Mode

Images with white backgrounds look harsh on dark surfaces. The filter: brightness() approach dims images slightly in dark mode to blend them into the darker environment. For SVGs, use currentColor to make strokes and fills adapt to the text color automatically.

dark-mode-images.css
CSS
1/* Dim images in dark mode */
2.dark img:not([src*=".svg"]) {
3 filter: brightness(0.85) contrast(1.05);
4}
5
6/* Logo swapping */
7.logo-light { display: block; }
8.logo-dark { display: none; }
9
10.dark .logo-light { display: none; }
11.dark .logo-dark { display: block; }
12
13/* Or use the picture element */
14/* <picture>
15 <source srcset="logo-dark.svg" media="(prefers-color-scheme: dark)" />
16 <img src="logo-light.svg" alt="Logo" />
17</picture> */
18
19/* SVG that adapts to theme */
20.icon {
21 width: 24px;
22 height: 24px;
23 color: var(--text-base);
24 fill: currentColor;
25 stroke: currentColor;
26}
27
28/* Dark-mode-specific image via CSS */
29.hero-image {
30 background-image: url("/images/hero-light.png");
31}
32
33.dark .hero-image {
34 background-image: url("/images/hero-dark.png");
35}
36
37/* Inline SVG with theme-aware colors */
38.svg-icon path {
39 fill: var(--text-base);
40 transition: fill 0.3s ease;
41}
preview
Focus Styles in Both Themes

Focus indicators are a WCAG 2.1 requirement and one of the most commonly broken elements in dark mode implementations. A blue outline that's visible on a white background may be invisible on dark surfaces. Your focus ring must use tokens that adapt to both themes.

focus-styles.css
CSS
1/* Double-ring focus: inner ring matches bg, outer ring is accent */
2:focus-visible {
3 outline: none;
4 box-shadow:
5 0 0 0 2px var(--bg-base),
6 0 0 0 4px var(--accent-base);
7}
8
9/* Works in both themes because tokens adapt */
10/* Light: white inner ring + green outer ring on white bg */
11/* Dark: dark inner ring + green outer ring on dark bg */
12
13/* Interactive elements need clear focus + hover states */
14.button {
15 background: var(--accent-base);
16 color: var(--text-inverse);
17 border: none;
18 padding: 10px 20px;
19 border-radius: var(--radius-md);
20 font-weight: 600;
21 cursor: pointer;
22 transition:
23 background-color var(--transition-fast),
24 box-shadow var(--transition-fast),
25 transform var(--transition-fast);
26}
27
28.button:hover {
29 background: var(--accent-hover);
30 transform: translateY(-1px);
31}
32
33.button:active {
34 background: var(--accent-active);
35 transform: translateY(0);
36}
37
38.button:focus-visible {
39 box-shadow:
40 0 0 0 2px var(--bg-base),
41 0 0 0 4px var(--accent-base),
42 0 4px 12px var(--accent-subtle);
43}
44
45/* Link focus */
46a:focus-visible {
47 outline: 2px solid var(--accent-base);
48 outline-offset: 2px;
49 border-radius: 2px;
50}
Common Mistakes

Dark mode implementations fail in predictable ways. Here are the most frequent pitfalls and their fixes. Each mistake compounds — a site that hardcodes colors and ignores contrast will have a dark mode that's worse than no dark mode at all.

MistakeImpactFix
Hardcoded colorsColors don't change with themeUse CSS variables for every color value
No focus states in dark modeKeyboard users can't navigateTest focus rings in both themes
Low contrast in dark modeText unreadable for low-vision usersCheck all combinations with contrast checker
No FOUC preventionFlash of wrong theme on loadInline script in <head> before paint
White images on dark bgHarsh contrast, visual noiseUse filter: brightness() or dark variants
Ignoring reduced motionMotion-sensitive users get nauseatedDisable transitions under prefers-reduced-motion
No localStorage persistencePreference resets on every visitStore choice and read on page load
Forgetting form controlsNative inputs stay white in dark modeUse color-scheme: dark on inputs

info

Always test both themes on real devices, not just in DevTools. DevTools theme switching doesn't accurately simulate system preference detection, prefers-color-scheme media queries, or the FOUC behavior that users experience on real page loads.
Best Practices Checklist

Use this checklist when implementing or auditing a dark mode system. Every item directly impacts usability, accessibility, or developer experience.

CategoryChecklist ItemPriority
TokensAll colors defined as CSS custom propertiesCritical
TokensSemantic naming (not raw color values)High
TokensShadows and borders are theme-awareHigh
FOUCInline script in <head> prevents flashCritical
FOUCcolor-scheme meta/CSS for browser chromeHigh
A11yWCAG AA contrast (4.5:1) in both themesCritical
A11yFocus indicators visible in both themesCritical
A11yprefers-reduced-motion disables transitionsHigh
UXSmooth transition between themes (0.3s)Medium
UXPreference persisted in localStorageHigh
UXSystem preference respected as defaultMedium
ImagesDark variants or dimming for imagesMedium
ImagesSVGs use currentColor for adaptationMedium
FormsForm controls themed via color-schemeHigh
TestingBoth themes tested on real devicesHigh
$Blueprint — Engineering Documentation·Section ID: CSS-DARK-MODE·Revision: 1.0