8 CSS Navbar Designs07 / 08
CSS Navbar with Dark Mode Toggle
A CSS navbar with a built-in dark mode toggle that flips the entire UI in under half a second — proving that semantic design tokens beat a `prefers-color-scheme` media query when you want users to control the theme themselves. The frosted backdrop-filter navbar carries a Linea wordmark + version chip, 5 active-dot nav links (Overview / Components / Templates / Docs / Changelog), and a custom track-and-thumb theme toggle that transitions between sun and moon icons with a 0.45s ease. Click triggers a radial flash overlay that ripples outward as the body recolors. Below the navbar: a hero with a live token preview panel (4 swatch cards for `--bg`, `--text`, `--accent`, `--border` updating their hex values in real time) + a `[data-theme]` CSS code block that re-renders + a stats strip (48 Tokens / 2 Themes / 0.45s Transition). Bottom features grid covers semantic-token theming, CSS-only transitions, WCAG AA contrast, and `localStorage` persistence. Epilogue + Fira Code. Best for design system docs, developer tool sites, modern SaaS landing pages, theme-toggle component galleries.
Published Updated
This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.
The code
<section class="nb-drk" data-theme="light" aria-label="CSS navbar with dark mode toggle demo">
<div class="theme-flash" data-nb-drk-flash aria-hidden="true"></div>
<nav aria-label="Primary">
<div class="nav-inner">
<a href="#" class="brand">
<div class="brand-mark">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" aria-hidden="true"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
</div>
<div>
<div class="brand-name">Linea</div>
<div class="brand-tag">v3.2.0</div>
</div>
</a>
<ul class="nav-links">
<li><a href="#" class="active"><span class="link-dot"></span>Overview</a></li>
<li><a href="#"><span class="link-dot"></span>Components</a></li>
<li><a href="#"><span class="link-dot"></span>Templates</a></li>
<li><a href="#"><span class="link-dot"></span>Docs</a></li>
<li><a href="#"><span class="link-dot"></span>Changelog</a></li>
</ul>
<div class="nav-spacer"></div>
<div class="nav-actions">
<button class="theme-toggle" type="button" data-nb-drk-toggle aria-label="Toggle dark mode">
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
<div class="toggle-track"><div class="toggle-thumb"></div></div>
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
<span class="toggle-label" data-nb-drk-label>Light</span>
</button>
<div class="nav-div" aria-hidden="true"></div>
<button class="btn-ghost" type="button">Sign in</button>
<button class="btn-fill" type="button">Get started</button>
</div>
</div>
</nav>
<div class="page">
<section class="hero">
<div class="hero-left">
<div class="hero-pill">Now in v3 — See what's new</div>
<h1>Design tokens<br>that <em>adapt</em><br>with you.</h1>
<p class="hero-body">Every color, shadow, and surface in this UI is driven by semantic CSS custom properties. Watch them all flip in under half a second — click the toggle above.</p>
<div class="hero-ctas">
<button class="cta-main" type="button">Browse Components →</button>
<a href="#" class="cta-link">
View on GitHub
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
</a>
</div>
</div>
<div class="hero-right">
<div class="preview-panel">
<p class="preview-label">Live token preview — toggle the theme above</p>
<div class="token-grid">
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="bg"></div>
<div class="token-name">--bg</div>
<div class="token-val" data-nb-drk-val="bg">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="text"></div>
<div class="token-name">--text</div>
<div class="token-val" data-nb-drk-val="text">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="accent"></div>
<div class="token-name">--accent</div>
<div class="token-val" data-nb-drk-val="accent">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="border"></div>
<div class="token-name">--border</div>
<div class="token-val" data-nb-drk-val="border">—</div>
</div>
</div>
<div class="code-block">
<span class="code-attr">[data-theme=<span class="code-val">"<span data-nb-drk-theme-in-code>light</span>"</span>]</span> {<br>
<span class="code-attr">--bg</span>: <span class="code-val" data-nb-drk-code="bg">#fafaf8</span>;<br>
<span class="code-attr">--text</span>: <span class="code-val" data-nb-drk-code="text">#18181a</span>;<br>
<span class="code-attr">--accent</span>: <span class="code-val" data-nb-drk-code="accent">#e84a2f</span>;<br>
<span class="code-attr">--surface</span>: <span class="code-val" data-nb-drk-code="surface">#ffffff</span>;<br>
}
</div>
<div class="stat-strip">
<div class="stat-item"><div class="stat-val">48</div><div class="stat-lbl">Tokens</div></div>
<div class="stat-item"><div class="stat-val">2</div><div class="stat-lbl">Themes</div></div>
<div class="stat-item"><div class="stat-val">0.45s</div><div class="stat-lbl">Transition</div></div>
</div>
</div>
</div>
</section>
<div class="features">
<div class="feature">
<div class="feature-icon">◑</div>
<div class="feature-title">Semantic tokens</div>
<div class="feature-desc">Every value maps to intent, not raw colors. Theme by switching a single attribute.</div>
</div>
<div class="feature">
<div class="feature-icon">⚡</div>
<div class="feature-title">CSS-only transitions</div>
<div class="feature-desc">No JavaScript required for the color shift. Pure CSS custom properties do the work.</div>
</div>
<div class="feature">
<div class="feature-icon">♿</div>
<div class="feature-title">WCAG AA+</div>
<div class="feature-desc">Both themes pass contrast requirements for text, borders, and interactive states.</div>
</div>
<div class="feature">
<div class="feature-icon">💾</div>
<div class="feature-title">Persisted preference</div>
<div class="feature-desc">Choice is saved to localStorage and respects prefers-color-scheme on first load.</div>
</div>
</div>
</div>
</section><section class="nb-drk" data-theme="light" aria-label="CSS navbar with dark mode toggle demo">
<div class="theme-flash" data-nb-drk-flash aria-hidden="true"></div>
<nav aria-label="Primary">
<div class="nav-inner">
<a href="#" class="brand">
<div class="brand-mark">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" aria-hidden="true"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
</div>
<div>
<div class="brand-name">Linea</div>
<div class="brand-tag">v3.2.0</div>
</div>
</a>
<ul class="nav-links">
<li><a href="#" class="active"><span class="link-dot"></span>Overview</a></li>
<li><a href="#"><span class="link-dot"></span>Components</a></li>
<li><a href="#"><span class="link-dot"></span>Templates</a></li>
<li><a href="#"><span class="link-dot"></span>Docs</a></li>
<li><a href="#"><span class="link-dot"></span>Changelog</a></li>
</ul>
<div class="nav-spacer"></div>
<div class="nav-actions">
<button class="theme-toggle" type="button" data-nb-drk-toggle aria-label="Toggle dark mode">
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
<div class="toggle-track"><div class="toggle-thumb"></div></div>
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
<span class="toggle-label" data-nb-drk-label>Light</span>
</button>
<div class="nav-div" aria-hidden="true"></div>
<button class="btn-ghost" type="button">Sign in</button>
<button class="btn-fill" type="button">Get started</button>
</div>
</div>
</nav>
<div class="page">
<section class="hero">
<div class="hero-left">
<div class="hero-pill">Now in v3 — See what's new</div>
<h1>Design tokens<br>that <em>adapt</em><br>with you.</h1>
<p class="hero-body">Every color, shadow, and surface in this UI is driven by semantic CSS custom properties. Watch them all flip in under half a second — click the toggle above.</p>
<div class="hero-ctas">
<button class="cta-main" type="button">Browse Components →</button>
<a href="#" class="cta-link">
View on GitHub
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
</a>
</div>
</div>
<div class="hero-right">
<div class="preview-panel">
<p class="preview-label">Live token preview — toggle the theme above</p>
<div class="token-grid">
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="bg"></div>
<div class="token-name">--bg</div>
<div class="token-val" data-nb-drk-val="bg">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="text"></div>
<div class="token-name">--text</div>
<div class="token-val" data-nb-drk-val="text">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="accent"></div>
<div class="token-name">--accent</div>
<div class="token-val" data-nb-drk-val="accent">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="border"></div>
<div class="token-name">--border</div>
<div class="token-val" data-nb-drk-val="border">—</div>
</div>
</div>
<div class="code-block">
<span class="code-attr">[data-theme=<span class="code-val">"<span data-nb-drk-theme-in-code>light</span>"</span>]</span> {<br>
<span class="code-attr">--bg</span>: <span class="code-val" data-nb-drk-code="bg">#fafaf8</span>;<br>
<span class="code-attr">--text</span>: <span class="code-val" data-nb-drk-code="text">#18181a</span>;<br>
<span class="code-attr">--accent</span>: <span class="code-val" data-nb-drk-code="accent">#e84a2f</span>;<br>
<span class="code-attr">--surface</span>: <span class="code-val" data-nb-drk-code="surface">#ffffff</span>;<br>
}
</div>
<div class="stat-strip">
<div class="stat-item"><div class="stat-val">48</div><div class="stat-lbl">Tokens</div></div>
<div class="stat-item"><div class="stat-val">2</div><div class="stat-lbl">Themes</div></div>
<div class="stat-item"><div class="stat-val">0.45s</div><div class="stat-lbl">Transition</div></div>
</div>
</div>
</div>
</section>
<div class="features">
<div class="feature">
<div class="feature-icon">◑</div>
<div class="feature-title">Semantic tokens</div>
<div class="feature-desc">Every value maps to intent, not raw colors. Theme by switching a single attribute.</div>
</div>
<div class="feature">
<div class="feature-icon">⚡</div>
<div class="feature-title">CSS-only transitions</div>
<div class="feature-desc">No JavaScript required for the color shift. Pure CSS custom properties do the work.</div>
</div>
<div class="feature">
<div class="feature-icon">♿</div>
<div class="feature-title">WCAG AA+</div>
<div class="feature-desc">Both themes pass contrast requirements for text, borders, and interactive states.</div>
</div>
<div class="feature">
<div class="feature-icon">💾</div>
<div class="feature-title">Persisted preference</div>
<div class="feature-desc">Choice is saved to localStorage and respects prefers-color-scheme on first load.</div>
</div>
</div>
</div>
</section>/* ─── 07 Linea — CSS navbar with dark mode toggle UI ──────────── */
@import url('https://fonts.googleapis.com/css2?family=Epilogue:ital,wght@0,300;0,400;0,500;0,700;0,900;1,300;1,700&family=Fira+Code:wght@300;400;500&display=swap');
.nb-drk {
--nb-drk-ease: cubic-bezier(0.4, 0, 0.2, 1);
--nb-drk-dur: 0.45s;
position: relative;
width: 100%;
min-height: 720px;
font-family: 'Epilogue', sans-serif;
overflow: hidden;
box-sizing: border-box;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk *,
.nb-drk *::before,
.nb-drk *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.nb-drk[data-theme="light"] {
--nb-drk-bg: #fafaf8;
--nb-drk-bg-2: #f2f1ee;
--nb-drk-surface: #ffffff;
--nb-drk-surface-float: rgba(255,255,255,0.85);
--nb-drk-border: #e4e2dc;
--nb-drk-border-soft: rgba(0,0,0,0.06);
--nb-drk-text: #18181a;
--nb-drk-text-2: #5a5856;
--nb-drk-text-3: #a09e99;
--nb-drk-accent: #e84a2f;
--nb-drk-accent-bg: rgba(232,74,47,0.08);
--nb-drk-toggle-track: #e4e2dc;
--nb-drk-toggle-thumb: #18181a;
--nb-drk-shadow-nav: 0 1px 0 var(--nb-drk-border), 0 4px 24px rgba(0,0,0,0.05);
--nb-drk-shadow-card: 0 2px 16px rgba(0,0,0,0.07);
--nb-drk-invert-text: #fafaf8;
}
.nb-drk[data-theme="dark"] {
--nb-drk-bg: #111113;
--nb-drk-bg-2: #19191c;
--nb-drk-surface: #1e1e22;
--nb-drk-surface-float: rgba(22,22,26,0.88);
--nb-drk-border: #2e2e34;
--nb-drk-border-soft: rgba(255,255,255,0.06);
--nb-drk-text: #f0efec;
--nb-drk-text-2: #9e9c97;
--nb-drk-text-3: #5c5a57;
--nb-drk-accent: #ff6b4a;
--nb-drk-accent-bg: rgba(255,107,74,0.1);
--nb-drk-toggle-track: #2e2e34;
--nb-drk-toggle-thumb: #f0efec;
--nb-drk-shadow-nav: 0 1px 0 var(--nb-drk-border), 0 4px 32px rgba(0,0,0,0.3);
--nb-drk-shadow-card: 0 2px 20px rgba(0,0,0,0.3);
--nb-drk-invert-text: #111113;
}
.nb-drk {
background: var(--nb-drk-bg);
color: var(--nb-drk-text);
}
.nb-drk nav {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 100;
height: 64px;
background: var(--nb-drk-surface-float);
backdrop-filter: blur(20px) saturate(150%);
-webkit-backdrop-filter: blur(20px) saturate(150%);
border-bottom: 1px solid var(--nb-drk-border);
box-shadow: var(--nb-drk-shadow-nav);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), box-shadow var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-inner {
max-width: 1280px;
margin: 0 auto;
height: 100%;
display: flex;
align-items: center;
padding: 0 2rem;
gap: 2rem;
}
.nb-drk .brand {
text-decoration: none;
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.nb-drk .brand-mark {
width: 28px;
height: 28px;
border-radius: 7px;
background: var(--nb-drk-accent);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .brand-mark svg {
display: block;
}
.nb-drk .brand-name {
font-size: 1rem;
font-weight: 700;
letter-spacing: -0.02em;
color: var(--nb-drk-text);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .brand-tag {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
font-weight: 300;
color: var(--nb-drk-text-3);
letter-spacing: 0.04em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-links {
display: flex;
align-items: center;
gap: 0;
list-style: none;
flex: 1;
}
.nb-drk .nav-links a {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.8rem;
font-weight: 500;
color: var(--nb-drk-text-2);
text-decoration: none;
padding: 7px 13px;
border-radius: 8px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), background 0.18s var(--nb-drk-ease);
white-space: nowrap;
}
.nb-drk .nav-links a:hover {
color: var(--nb-drk-text);
background: var(--nb-drk-border-soft);
}
.nb-drk .nav-links a.active {
color: var(--nb-drk-text);
background: var(--nb-drk-accent-bg);
}
.nb-drk .nav-links a.active .link-dot {
background: var(--nb-drk-accent);
}
.nb-drk .link-dot {
width: 5px;
height: 5px;
border-radius: 50%;
background: transparent;
flex-shrink: 0;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-spacer {
flex: 1;
}
.nb-drk .nav-actions {
display: flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
}
.nb-drk .theme-toggle {
display: flex;
align-items: center;
gap: 9px;
background: none;
border: none;
cursor: pointer;
padding: 6px 10px;
border-radius: 10px;
transition: background 0.18s;
font-family: inherit;
color: inherit;
}
.nb-drk .theme-toggle:hover {
background: var(--nb-drk-border-soft);
}
.nb-drk .toggle-track {
width: 36px;
height: 20px;
border-radius: 100px;
background: var(--nb-drk-toggle-track);
border: 1.5px solid var(--nb-drk-border);
position: relative;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
flex-shrink: 0;
}
.nb-drk .toggle-thumb {
position: absolute;
top: 2px;
left: 2px;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--nb-drk-toggle-thumb);
transition: transform var(--nb-drk-dur) cubic-bezier(0.34, 1.56, 0.64, 1), background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk[data-theme="dark"] .toggle-thumb {
transform: translateX(16px);
}
.nb-drk .icon-sun,
.nb-drk .icon-moon {
width: 14px;
height: 14px;
transition: opacity 0.3s var(--nb-drk-ease), transform 0.4s var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
color: var(--nb-drk-text-2);
}
.nb-drk[data-theme="light"] .icon-sun {
opacity: 1;
transform: rotate(0deg);
}
.nb-drk[data-theme="light"] .icon-moon {
opacity: 0.3;
}
.nb-drk[data-theme="dark"] .icon-moon {
opacity: 1;
transform: rotate(-15deg);
}
.nb-drk[data-theme="dark"] .icon-sun {
opacity: 0.3;
}
.nb-drk .toggle-label {
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
color: var(--nb-drk-text-3);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
white-space: nowrap;
}
.nb-drk .nav-div {
width: 1px;
height: 20px;
background: var(--nb-drk-border);
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .btn-ghost {
font-family: 'Epilogue', sans-serif;
font-size: 0.78rem;
font-weight: 500;
color: var(--nb-drk-text-2);
background: none;
border: 1px solid var(--nb-drk-border);
border-radius: 8px;
padding: 7px 15px;
cursor: pointer;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), background 0.18s;
white-space: nowrap;
}
.nb-drk .btn-ghost:hover {
color: var(--nb-drk-text);
border-color: var(--nb-drk-text-3);
}
.nb-drk .btn-fill {
font-family: 'Epilogue', sans-serif;
font-size: 0.78rem;
font-weight: 700;
color: var(--nb-drk-invert-text);
background: var(--nb-drk-text);
border: none;
border-radius: 8px;
padding: 7px 16px;
cursor: pointer;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease), transform 0.15s;
white-space: nowrap;
}
.nb-drk .btn-fill:hover {
transform: translateY(-1px);
}
.nb-drk .page {
padding-top: 64px;
}
.nb-drk .hero {
min-height: 560px;
display: grid;
grid-template-columns: 1fr 1fr;
}
.nb-drk .hero-left {
padding: 5rem 4rem;
display: flex;
flex-direction: column;
justify-content: center;
border-right: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-pill {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
font-weight: 400;
color: var(--nb-drk-accent);
background: var(--nb-drk-accent-bg);
border: 1px solid rgba(232,74,47,0.15);
border-radius: 100px;
padding: 5px 12px;
margin-bottom: 2rem;
width: fit-content;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-pill::before {
content: '◉';
font-size: 0.55rem;
}
.nb-drk h1 {
font-size: clamp(2.8rem, 4.5vw, 5rem);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 1.0;
color: var(--nb-drk-text);
margin-bottom: 1.5rem;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk h1 em {
font-style: italic;
font-weight: 300;
color: var(--nb-drk-accent);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-body {
font-size: 1rem;
color: var(--nb-drk-text-2);
line-height: 1.7;
max-width: 42ch;
margin-bottom: 2.5rem;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-ctas {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
}
.nb-drk .cta-main {
font-family: 'Epilogue', sans-serif;
font-size: 0.82rem;
font-weight: 700;
color: var(--nb-drk-invert-text);
background: var(--nb-drk-text);
border: none;
border-radius: 10px;
padding: 12px 22px;
cursor: pointer;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease), transform 0.15s;
}
.nb-drk .cta-main:hover {
transform: translateY(-2px);
}
.nb-drk .cta-link {
font-size: 0.82rem;
font-weight: 500;
color: var(--nb-drk-text-2);
text-decoration: none;
transition: color 0.2s;
display: flex;
align-items: center;
gap: 6px;
}
.nb-drk .cta-link:hover {
color: var(--nb-drk-text);
}
.nb-drk .hero-right {
padding: 3rem;
display: flex;
align-items: center;
justify-content: center;
background: var(--nb-drk-bg-2);
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .preview-panel {
width: 100%;
max-width: 400px;
display: flex;
flex-direction: column;
gap: 12px;
}
.nb-drk .preview-label {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--nb-drk-text-3);
margin-bottom: 4px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .token-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-bottom: 4px;
}
.nb-drk .token-card {
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
padding: 12px 14px;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), box-shadow var(--nb-drk-dur) var(--nb-drk-ease);
box-shadow: var(--nb-drk-shadow-card);
}
.nb-drk .token-swatch {
width: 20px;
height: 20px;
border-radius: 5px;
margin-bottom: 8px;
border: 1px solid var(--nb-drk-border-soft);
}
.nb-drk .token-name {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
color: var(--nb-drk-text-3);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
margin-bottom: 2px;
}
.nb-drk .token-val {
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
color: var(--nb-drk-text);
font-weight: 500;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .code-block {
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
padding: 14px 16px;
font-family: 'Fira Code', monospace;
font-size: 0.68rem;
line-height: 1.8;
color: var(--nb-drk-text-2);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
box-shadow: var(--nb-drk-shadow-card);
}
.nb-drk .code-attr {
color: var(--nb-drk-accent);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .code-val {
color: var(--nb-drk-text);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-strip {
display: flex;
gap: 0;
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
overflow: hidden;
box-shadow: var(--nb-drk-shadow-card);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-item {
flex: 1;
padding: 12px 14px;
border-right: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-item:last-child {
border-right: none;
}
.nb-drk .stat-val {
font-size: 1.2rem;
font-weight: 900;
letter-spacing: -0.03em;
color: var(--nb-drk-text);
line-height: 1;
margin-bottom: 3px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-lbl {
font-size: 0.62rem;
color: var(--nb-drk-text-3);
font-weight: 500;
letter-spacing: 0.04em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .theme-flash {
position: absolute;
inset: 0;
z-index: 99;
pointer-events: none;
opacity: 0;
border-radius: 50%;
transform: scale(0);
}
.nb-drk .theme-flash.animate {
animation: nb-drk-ripple 0.55s ease-out forwards;
}
@keyframes nb-drk-ripple {
0% {
opacity: 0.12;
transform: scale(0);
border-radius: 50%;
}
60% {
opacity: 0.06;
transform: scale(3);
}
100% {
opacity: 0;
transform: scale(5);
}
}
.nb-drk .features {
display: grid;
grid-template-columns: repeat(4, 1fr);
border-top: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature {
padding: 2.5rem 2rem;
border-right: 1px solid var(--nb-drk-border);
transition: background 0.2s, border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature:last-child {
border-right: none;
}
.nb-drk .feature:hover {
background: var(--nb-drk-bg-2);
}
.nb-drk .feature-icon {
width: 36px;
height: 36px;
border-radius: 9px;
background: var(--nb-drk-accent-bg);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1rem;
color: var(--nb-drk-accent);
font-size: 1rem;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature-title {
font-size: 0.88rem;
font-weight: 700;
color: var(--nb-drk-text);
margin-bottom: 0.4rem;
letter-spacing: -0.01em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature-desc {
font-size: 0.78rem;
color: var(--nb-drk-text-2);
line-height: 1.6;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
@media (max-width: 900px) {
.nb-drk .hero {
grid-template-columns: 1fr;
}
.nb-drk .hero-left {
border-right: none;
border-bottom: 1px solid var(--nb-drk-border);
padding: 3rem 2rem;
}
.nb-drk .hero-right {
padding: 2rem;
}
.nb-drk .features {
grid-template-columns: 1fr 1fr;
}
.nb-drk .feature:nth-child(2) {
border-right: none;
}
.nb-drk .feature:nth-child(3),
.nb-drk .feature:nth-child(4) {
border-top: 1px solid var(--nb-drk-border);
}
.nb-drk .nav-links {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.nb-drk *,
.nb-drk *::before,
.nb-drk *::after {
transition: none !important;
animation: none !important;
}
}/* ─── 07 Linea — CSS navbar with dark mode toggle UI ──────────── */
@import url('https://fonts.googleapis.com/css2?family=Epilogue:ital,wght@0,300;0,400;0,500;0,700;0,900;1,300;1,700&family=Fira+Code:wght@300;400;500&display=swap');
.nb-drk {
--nb-drk-ease: cubic-bezier(0.4, 0, 0.2, 1);
--nb-drk-dur: 0.45s;
position: relative;
width: 100%;
min-height: 720px;
font-family: 'Epilogue', sans-serif;
overflow: hidden;
box-sizing: border-box;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk *,
.nb-drk *::before,
.nb-drk *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.nb-drk[data-theme="light"] {
--nb-drk-bg: #fafaf8;
--nb-drk-bg-2: #f2f1ee;
--nb-drk-surface: #ffffff;
--nb-drk-surface-float: rgba(255,255,255,0.85);
--nb-drk-border: #e4e2dc;
--nb-drk-border-soft: rgba(0,0,0,0.06);
--nb-drk-text: #18181a;
--nb-drk-text-2: #5a5856;
--nb-drk-text-3: #a09e99;
--nb-drk-accent: #e84a2f;
--nb-drk-accent-bg: rgba(232,74,47,0.08);
--nb-drk-toggle-track: #e4e2dc;
--nb-drk-toggle-thumb: #18181a;
--nb-drk-shadow-nav: 0 1px 0 var(--nb-drk-border), 0 4px 24px rgba(0,0,0,0.05);
--nb-drk-shadow-card: 0 2px 16px rgba(0,0,0,0.07);
--nb-drk-invert-text: #fafaf8;
}
.nb-drk[data-theme="dark"] {
--nb-drk-bg: #111113;
--nb-drk-bg-2: #19191c;
--nb-drk-surface: #1e1e22;
--nb-drk-surface-float: rgba(22,22,26,0.88);
--nb-drk-border: #2e2e34;
--nb-drk-border-soft: rgba(255,255,255,0.06);
--nb-drk-text: #f0efec;
--nb-drk-text-2: #9e9c97;
--nb-drk-text-3: #5c5a57;
--nb-drk-accent: #ff6b4a;
--nb-drk-accent-bg: rgba(255,107,74,0.1);
--nb-drk-toggle-track: #2e2e34;
--nb-drk-toggle-thumb: #f0efec;
--nb-drk-shadow-nav: 0 1px 0 var(--nb-drk-border), 0 4px 32px rgba(0,0,0,0.3);
--nb-drk-shadow-card: 0 2px 20px rgba(0,0,0,0.3);
--nb-drk-invert-text: #111113;
}
.nb-drk {
background: var(--nb-drk-bg);
color: var(--nb-drk-text);
}
.nb-drk nav {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 100;
height: 64px;
background: var(--nb-drk-surface-float);
backdrop-filter: blur(20px) saturate(150%);
-webkit-backdrop-filter: blur(20px) saturate(150%);
border-bottom: 1px solid var(--nb-drk-border);
box-shadow: var(--nb-drk-shadow-nav);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), box-shadow var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-inner {
max-width: 1280px;
margin: 0 auto;
height: 100%;
display: flex;
align-items: center;
padding: 0 2rem;
gap: 2rem;
}
.nb-drk .brand {
text-decoration: none;
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.nb-drk .brand-mark {
width: 28px;
height: 28px;
border-radius: 7px;
background: var(--nb-drk-accent);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .brand-mark svg {
display: block;
}
.nb-drk .brand-name {
font-size: 1rem;
font-weight: 700;
letter-spacing: -0.02em;
color: var(--nb-drk-text);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .brand-tag {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
font-weight: 300;
color: var(--nb-drk-text-3);
letter-spacing: 0.04em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-links {
display: flex;
align-items: center;
gap: 0;
list-style: none;
flex: 1;
}
.nb-drk .nav-links a {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.8rem;
font-weight: 500;
color: var(--nb-drk-text-2);
text-decoration: none;
padding: 7px 13px;
border-radius: 8px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), background 0.18s var(--nb-drk-ease);
white-space: nowrap;
}
.nb-drk .nav-links a:hover {
color: var(--nb-drk-text);
background: var(--nb-drk-border-soft);
}
.nb-drk .nav-links a.active {
color: var(--nb-drk-text);
background: var(--nb-drk-accent-bg);
}
.nb-drk .nav-links a.active .link-dot {
background: var(--nb-drk-accent);
}
.nb-drk .link-dot {
width: 5px;
height: 5px;
border-radius: 50%;
background: transparent;
flex-shrink: 0;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-spacer {
flex: 1;
}
.nb-drk .nav-actions {
display: flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
}
.nb-drk .theme-toggle {
display: flex;
align-items: center;
gap: 9px;
background: none;
border: none;
cursor: pointer;
padding: 6px 10px;
border-radius: 10px;
transition: background 0.18s;
font-family: inherit;
color: inherit;
}
.nb-drk .theme-toggle:hover {
background: var(--nb-drk-border-soft);
}
.nb-drk .toggle-track {
width: 36px;
height: 20px;
border-radius: 100px;
background: var(--nb-drk-toggle-track);
border: 1.5px solid var(--nb-drk-border);
position: relative;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
flex-shrink: 0;
}
.nb-drk .toggle-thumb {
position: absolute;
top: 2px;
left: 2px;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--nb-drk-toggle-thumb);
transition: transform var(--nb-drk-dur) cubic-bezier(0.34, 1.56, 0.64, 1), background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk[data-theme="dark"] .toggle-thumb {
transform: translateX(16px);
}
.nb-drk .icon-sun,
.nb-drk .icon-moon {
width: 14px;
height: 14px;
transition: opacity 0.3s var(--nb-drk-ease), transform 0.4s var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
color: var(--nb-drk-text-2);
}
.nb-drk[data-theme="light"] .icon-sun {
opacity: 1;
transform: rotate(0deg);
}
.nb-drk[data-theme="light"] .icon-moon {
opacity: 0.3;
}
.nb-drk[data-theme="dark"] .icon-moon {
opacity: 1;
transform: rotate(-15deg);
}
.nb-drk[data-theme="dark"] .icon-sun {
opacity: 0.3;
}
.nb-drk .toggle-label {
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
color: var(--nb-drk-text-3);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
white-space: nowrap;
}
.nb-drk .nav-div {
width: 1px;
height: 20px;
background: var(--nb-drk-border);
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .btn-ghost {
font-family: 'Epilogue', sans-serif;
font-size: 0.78rem;
font-weight: 500;
color: var(--nb-drk-text-2);
background: none;
border: 1px solid var(--nb-drk-border);
border-radius: 8px;
padding: 7px 15px;
cursor: pointer;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), background 0.18s;
white-space: nowrap;
}
.nb-drk .btn-ghost:hover {
color: var(--nb-drk-text);
border-color: var(--nb-drk-text-3);
}
.nb-drk .btn-fill {
font-family: 'Epilogue', sans-serif;
font-size: 0.78rem;
font-weight: 700;
color: var(--nb-drk-invert-text);
background: var(--nb-drk-text);
border: none;
border-radius: 8px;
padding: 7px 16px;
cursor: pointer;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease), transform 0.15s;
white-space: nowrap;
}
.nb-drk .btn-fill:hover {
transform: translateY(-1px);
}
.nb-drk .page {
padding-top: 64px;
}
.nb-drk .hero {
min-height: 560px;
display: grid;
grid-template-columns: 1fr 1fr;
}
.nb-drk .hero-left {
padding: 5rem 4rem;
display: flex;
flex-direction: column;
justify-content: center;
border-right: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-pill {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
font-weight: 400;
color: var(--nb-drk-accent);
background: var(--nb-drk-accent-bg);
border: 1px solid rgba(232,74,47,0.15);
border-radius: 100px;
padding: 5px 12px;
margin-bottom: 2rem;
width: fit-content;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-pill::before {
content: '◉';
font-size: 0.55rem;
}
.nb-drk h1 {
font-size: clamp(2.8rem, 4.5vw, 5rem);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 1.0;
color: var(--nb-drk-text);
margin-bottom: 1.5rem;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk h1 em {
font-style: italic;
font-weight: 300;
color: var(--nb-drk-accent);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-body {
font-size: 1rem;
color: var(--nb-drk-text-2);
line-height: 1.7;
max-width: 42ch;
margin-bottom: 2.5rem;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-ctas {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
}
.nb-drk .cta-main {
font-family: 'Epilogue', sans-serif;
font-size: 0.82rem;
font-weight: 700;
color: var(--nb-drk-invert-text);
background: var(--nb-drk-text);
border: none;
border-radius: 10px;
padding: 12px 22px;
cursor: pointer;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease), transform 0.15s;
}
.nb-drk .cta-main:hover {
transform: translateY(-2px);
}
.nb-drk .cta-link {
font-size: 0.82rem;
font-weight: 500;
color: var(--nb-drk-text-2);
text-decoration: none;
transition: color 0.2s;
display: flex;
align-items: center;
gap: 6px;
}
.nb-drk .cta-link:hover {
color: var(--nb-drk-text);
}
.nb-drk .hero-right {
padding: 3rem;
display: flex;
align-items: center;
justify-content: center;
background: var(--nb-drk-bg-2);
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .preview-panel {
width: 100%;
max-width: 400px;
display: flex;
flex-direction: column;
gap: 12px;
}
.nb-drk .preview-label {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--nb-drk-text-3);
margin-bottom: 4px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .token-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-bottom: 4px;
}
.nb-drk .token-card {
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
padding: 12px 14px;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), box-shadow var(--nb-drk-dur) var(--nb-drk-ease);
box-shadow: var(--nb-drk-shadow-card);
}
.nb-drk .token-swatch {
width: 20px;
height: 20px;
border-radius: 5px;
margin-bottom: 8px;
border: 1px solid var(--nb-drk-border-soft);
}
.nb-drk .token-name {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
color: var(--nb-drk-text-3);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
margin-bottom: 2px;
}
.nb-drk .token-val {
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
color: var(--nb-drk-text);
font-weight: 500;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .code-block {
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
padding: 14px 16px;
font-family: 'Fira Code', monospace;
font-size: 0.68rem;
line-height: 1.8;
color: var(--nb-drk-text-2);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
box-shadow: var(--nb-drk-shadow-card);
}
.nb-drk .code-attr {
color: var(--nb-drk-accent);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .code-val {
color: var(--nb-drk-text);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-strip {
display: flex;
gap: 0;
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
overflow: hidden;
box-shadow: var(--nb-drk-shadow-card);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-item {
flex: 1;
padding: 12px 14px;
border-right: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-item:last-child {
border-right: none;
}
.nb-drk .stat-val {
font-size: 1.2rem;
font-weight: 900;
letter-spacing: -0.03em;
color: var(--nb-drk-text);
line-height: 1;
margin-bottom: 3px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-lbl {
font-size: 0.62rem;
color: var(--nb-drk-text-3);
font-weight: 500;
letter-spacing: 0.04em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .theme-flash {
position: absolute;
inset: 0;
z-index: 99;
pointer-events: none;
opacity: 0;
border-radius: 50%;
transform: scale(0);
}
.nb-drk .theme-flash.animate {
animation: nb-drk-ripple 0.55s ease-out forwards;
}
@keyframes nb-drk-ripple {
0% {
opacity: 0.12;
transform: scale(0);
border-radius: 50%;
}
60% {
opacity: 0.06;
transform: scale(3);
}
100% {
opacity: 0;
transform: scale(5);
}
}
.nb-drk .features {
display: grid;
grid-template-columns: repeat(4, 1fr);
border-top: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature {
padding: 2.5rem 2rem;
border-right: 1px solid var(--nb-drk-border);
transition: background 0.2s, border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature:last-child {
border-right: none;
}
.nb-drk .feature:hover {
background: var(--nb-drk-bg-2);
}
.nb-drk .feature-icon {
width: 36px;
height: 36px;
border-radius: 9px;
background: var(--nb-drk-accent-bg);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1rem;
color: var(--nb-drk-accent);
font-size: 1rem;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature-title {
font-size: 0.88rem;
font-weight: 700;
color: var(--nb-drk-text);
margin-bottom: 0.4rem;
letter-spacing: -0.01em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature-desc {
font-size: 0.78rem;
color: var(--nb-drk-text-2);
line-height: 1.6;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
@media (max-width: 900px) {
.nb-drk .hero {
grid-template-columns: 1fr;
}
.nb-drk .hero-left {
border-right: none;
border-bottom: 1px solid var(--nb-drk-border);
padding: 3rem 2rem;
}
.nb-drk .hero-right {
padding: 2rem;
}
.nb-drk .features {
grid-template-columns: 1fr 1fr;
}
.nb-drk .feature:nth-child(2) {
border-right: none;
}
.nb-drk .feature:nth-child(3),
.nb-drk .feature:nth-child(4) {
border-top: 1px solid var(--nb-drk-border);
}
.nb-drk .nav-links {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.nb-drk *,
.nb-drk *::before,
.nb-drk *::after {
transition: none !important;
animation: none !important;
}
}(() => {
// Scoped dark-mode toggle. Theme attribute lives on the wrapper, not
// <html>, so multiple instances on a page each carry their own theme
// state. The source mock used localStorage + prefers-color-scheme —
// both dropped because the embedded demo doesn't own the host page's
// theme preference. The radial flash overlay is bounded to the
// wrapper (position:absolute) so it doesn't escape into the gallery.
const root = document.querySelector('.nb-drk');
if (!root) return;
const toggle = root.querySelector('[data-nb-drk-toggle]');
const label = root.querySelector('[data-nb-drk-label]');
const flash = root.querySelector('[data-nb-drk-flash]');
if (!toggle || !label || !flash) return;
const tokens = {
light: { bg: '#fafaf8', text: '#18181a', accent: '#e84a2f', border: '#e4e2dc', surface: '#ffffff' },
dark: { bg: '#111113', text: '#f0efec', accent: '#ff6b4a', border: '#2e2e34', surface: '#1e1e22' },
};
function updatePreview(theme) {
const t = tokens[theme];
for (const key of ['bg', 'text', 'accent', 'border']) {
const valEl = root.querySelector('[data-nb-drk-val="' + key + '"]');
const swatchEl = root.querySelector('[data-nb-drk-swatch="' + key + '"]');
if (valEl) valEl.textContent = t[key];
if (swatchEl) swatchEl.style.background = t[key];
}
for (const key of ['bg', 'text', 'accent', 'surface']) {
const codeEl = root.querySelector('[data-nb-drk-code="' + key + '"]');
if (codeEl) codeEl.textContent = t[key];
}
const themeInCode = root.querySelector('[data-nb-drk-theme-in-code]');
if (themeInCode) themeInCode.textContent = theme;
label.textContent = theme === 'dark' ? 'Dark' : 'Light';
}
function triggerFlash(theme) {
flash.style.background = theme === 'dark' ? '#f0efec' : '#111113';
flash.classList.remove('animate');
// Force reflow so the animation restarts.
void flash.offsetWidth;
flash.classList.add('animate');
}
function applyTheme(theme) {
root.setAttribute('data-theme', theme);
updatePreview(theme);
}
// Seed from the wrapper's current data-theme (default "light" via HTML).
applyTheme(root.getAttribute('data-theme') || 'light');
toggle.addEventListener('click', () => {
const next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
triggerFlash(next);
applyTheme(next);
});
})();(() => {
// Scoped dark-mode toggle. Theme attribute lives on the wrapper, not
// <html>, so multiple instances on a page each carry their own theme
// state. The source mock used localStorage + prefers-color-scheme —
// both dropped because the embedded demo doesn't own the host page's
// theme preference. The radial flash overlay is bounded to the
// wrapper (position:absolute) so it doesn't escape into the gallery.
const root = document.querySelector('.nb-drk');
if (!root) return;
const toggle = root.querySelector('[data-nb-drk-toggle]');
const label = root.querySelector('[data-nb-drk-label]');
const flash = root.querySelector('[data-nb-drk-flash]');
if (!toggle || !label || !flash) return;
const tokens = {
light: { bg: '#fafaf8', text: '#18181a', accent: '#e84a2f', border: '#e4e2dc', surface: '#ffffff' },
dark: { bg: '#111113', text: '#f0efec', accent: '#ff6b4a', border: '#2e2e34', surface: '#1e1e22' },
};
function updatePreview(theme) {
const t = tokens[theme];
for (const key of ['bg', 'text', 'accent', 'border']) {
const valEl = root.querySelector('[data-nb-drk-val="' + key + '"]');
const swatchEl = root.querySelector('[data-nb-drk-swatch="' + key + '"]');
if (valEl) valEl.textContent = t[key];
if (swatchEl) swatchEl.style.background = t[key];
}
for (const key of ['bg', 'text', 'accent', 'surface']) {
const codeEl = root.querySelector('[data-nb-drk-code="' + key + '"]');
if (codeEl) codeEl.textContent = t[key];
}
const themeInCode = root.querySelector('[data-nb-drk-theme-in-code]');
if (themeInCode) themeInCode.textContent = theme;
label.textContent = theme === 'dark' ? 'Dark' : 'Light';
}
function triggerFlash(theme) {
flash.style.background = theme === 'dark' ? '#f0efec' : '#111113';
flash.classList.remove('animate');
// Force reflow so the animation restarts.
void flash.offsetWidth;
flash.classList.add('animate');
}
function applyTheme(theme) {
root.setAttribute('data-theme', theme);
updatePreview(theme);
}
// Seed from the wrapper's current data-theme (default "light" via HTML).
applyTheme(root.getAttribute('data-theme') || 'light');
toggle.addEventListener('click', () => {
const next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
triggerFlash(next);
applyTheme(next);
});
})();Here's a working CSS Navbar Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Navbar with Dark Mode Toggle
Source: https://codefronts.com/navigation/css-navbars/css-navbar-with-dark-mode-toggle/
A CSS navbar with a built-in dark mode toggle that flips the entire UI in under half a second — proving that semantic design tokens beat a `prefers-color-scheme` media query when you want users to control the theme themselves. The frosted backdrop-filter navbar carries a Linea wordmark + version chip, 5 active-dot nav links (Overview / Components / Templates / Docs / Changelog), and a custom track-and-thumb theme toggle that transitions between sun and moon icons with a 0.45s ease. Click triggers a radial flash overlay that ripples outward as the body recolors. Below the navbar: a hero with a live token preview panel (4 swatch cards for `--bg`, `--text`, `--accent`, `--border` updating their hex values in real time) + a `[data-theme]` CSS code block that re-renders + a stats strip (48 Tokens / 2 Themes / 0.45s Transition). Bottom features grid covers semantic-token theming, CSS-only transitions, WCAG AA contrast, and `localStorage` persistence. Epilogue + Fira Code. Best for design system docs, developer tool sites, modern SaaS landing pages, theme-toggle component galleries.
## HTML
```html
<section class="nb-drk" data-theme="light" aria-label="CSS navbar with dark mode toggle demo">
<div class="theme-flash" data-nb-drk-flash aria-hidden="true"></div>
<nav aria-label="Primary">
<div class="nav-inner">
<a href="#" class="brand">
<div class="brand-mark">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" aria-hidden="true"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
</div>
<div>
<div class="brand-name">Linea</div>
<div class="brand-tag">v3.2.0</div>
</div>
</a>
<ul class="nav-links">
<li><a href="#" class="active"><span class="link-dot"></span>Overview</a></li>
<li><a href="#"><span class="link-dot"></span>Components</a></li>
<li><a href="#"><span class="link-dot"></span>Templates</a></li>
<li><a href="#"><span class="link-dot"></span>Docs</a></li>
<li><a href="#"><span class="link-dot"></span>Changelog</a></li>
</ul>
<div class="nav-spacer"></div>
<div class="nav-actions">
<button class="theme-toggle" type="button" data-nb-drk-toggle aria-label="Toggle dark mode">
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
<div class="toggle-track"><div class="toggle-thumb"></div></div>
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
<span class="toggle-label" data-nb-drk-label>Light</span>
</button>
<div class="nav-div" aria-hidden="true"></div>
<button class="btn-ghost" type="button">Sign in</button>
<button class="btn-fill" type="button">Get started</button>
</div>
</div>
</nav>
<div class="page">
<section class="hero">
<div class="hero-left">
<div class="hero-pill">Now in v3 — See what's new</div>
<h1>Design tokens<br>that <em>adapt</em><br>with you.</h1>
<p class="hero-body">Every color, shadow, and surface in this UI is driven by semantic CSS custom properties. Watch them all flip in under half a second — click the toggle above.</p>
<div class="hero-ctas">
<button class="cta-main" type="button">Browse Components →</button>
<a href="#" class="cta-link">
View on GitHub
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
</a>
</div>
</div>
<div class="hero-right">
<div class="preview-panel">
<p class="preview-label">Live token preview — toggle the theme above</p>
<div class="token-grid">
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="bg"></div>
<div class="token-name">--bg</div>
<div class="token-val" data-nb-drk-val="bg">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="text"></div>
<div class="token-name">--text</div>
<div class="token-val" data-nb-drk-val="text">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="accent"></div>
<div class="token-name">--accent</div>
<div class="token-val" data-nb-drk-val="accent">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="border"></div>
<div class="token-name">--border</div>
<div class="token-val" data-nb-drk-val="border">—</div>
</div>
</div>
<div class="code-block">
<span class="code-attr">[data-theme=<span class="code-val">"<span data-nb-drk-theme-in-code>light</span>"</span>]</span> {<br>
<span class="code-attr">--bg</span>: <span class="code-val" data-nb-drk-code="bg">#fafaf8</span>;<br>
<span class="code-attr">--text</span>: <span class="code-val" data-nb-drk-code="text">#18181a</span>;<br>
<span class="code-attr">--accent</span>: <span class="code-val" data-nb-drk-code="accent">#e84a2f</span>;<br>
<span class="code-attr">--surface</span>: <span class="code-val" data-nb-drk-code="surface">#ffffff</span>;<br>
}
</div>
<div class="stat-strip">
<div class="stat-item"><div class="stat-val">48</div><div class="stat-lbl">Tokens</div></div>
<div class="stat-item"><div class="stat-val">2</div><div class="stat-lbl">Themes</div></div>
<div class="stat-item"><div class="stat-val">0.45s</div><div class="stat-lbl">Transition</div></div>
</div>
</div>
</div>
</section>
<div class="features">
<div class="feature">
<div class="feature-icon">◑</div>
<div class="feature-title">Semantic tokens</div>
<div class="feature-desc">Every value maps to intent, not raw colors. Theme by switching a single attribute.</div>
</div>
<div class="feature">
<div class="feature-icon">⚡</div>
<div class="feature-title">CSS-only transitions</div>
<div class="feature-desc">No JavaScript required for the color shift. Pure CSS custom properties do the work.</div>
</div>
<div class="feature">
<div class="feature-icon">♿</div>
<div class="feature-title">WCAG AA+</div>
<div class="feature-desc">Both themes pass contrast requirements for text, borders, and interactive states.</div>
</div>
<div class="feature">
<div class="feature-icon">💾</div>
<div class="feature-title">Persisted preference</div>
<div class="feature-desc">Choice is saved to localStorage and respects prefers-color-scheme on first load.</div>
</div>
</div>
</div>
</section>
```
## CSS
```css
/* ─── 07 Linea — CSS navbar with dark mode toggle UI ──────────── */
@import url('https://fonts.googleapis.com/css2?family=Epilogue:ital,wght@0,300;0,400;0,500;0,700;0,900;1,300;1,700&family=Fira+Code:wght@300;400;500&display=swap');
.nb-drk {
--nb-drk-ease: cubic-bezier(0.4, 0, 0.2, 1);
--nb-drk-dur: 0.45s;
position: relative;
width: 100%;
min-height: 720px;
font-family: 'Epilogue', sans-serif;
overflow: hidden;
box-sizing: border-box;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk *,
.nb-drk *::before,
.nb-drk *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.nb-drk[data-theme="light"] {
--nb-drk-bg: #fafaf8;
--nb-drk-bg-2: #f2f1ee;
--nb-drk-surface: #ffffff;
--nb-drk-surface-float: rgba(255,255,255,0.85);
--nb-drk-border: #e4e2dc;
--nb-drk-border-soft: rgba(0,0,0,0.06);
--nb-drk-text: #18181a;
--nb-drk-text-2: #5a5856;
--nb-drk-text-3: #a09e99;
--nb-drk-accent: #e84a2f;
--nb-drk-accent-bg: rgba(232,74,47,0.08);
--nb-drk-toggle-track: #e4e2dc;
--nb-drk-toggle-thumb: #18181a;
--nb-drk-shadow-nav: 0 1px 0 var(--nb-drk-border), 0 4px 24px rgba(0,0,0,0.05);
--nb-drk-shadow-card: 0 2px 16px rgba(0,0,0,0.07);
--nb-drk-invert-text: #fafaf8;
}
.nb-drk[data-theme="dark"] {
--nb-drk-bg: #111113;
--nb-drk-bg-2: #19191c;
--nb-drk-surface: #1e1e22;
--nb-drk-surface-float: rgba(22,22,26,0.88);
--nb-drk-border: #2e2e34;
--nb-drk-border-soft: rgba(255,255,255,0.06);
--nb-drk-text: #f0efec;
--nb-drk-text-2: #9e9c97;
--nb-drk-text-3: #5c5a57;
--nb-drk-accent: #ff6b4a;
--nb-drk-accent-bg: rgba(255,107,74,0.1);
--nb-drk-toggle-track: #2e2e34;
--nb-drk-toggle-thumb: #f0efec;
--nb-drk-shadow-nav: 0 1px 0 var(--nb-drk-border), 0 4px 32px rgba(0,0,0,0.3);
--nb-drk-shadow-card: 0 2px 20px rgba(0,0,0,0.3);
--nb-drk-invert-text: #111113;
}
.nb-drk {
background: var(--nb-drk-bg);
color: var(--nb-drk-text);
}
.nb-drk nav {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 100;
height: 64px;
background: var(--nb-drk-surface-float);
backdrop-filter: blur(20px) saturate(150%);
-webkit-backdrop-filter: blur(20px) saturate(150%);
border-bottom: 1px solid var(--nb-drk-border);
box-shadow: var(--nb-drk-shadow-nav);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), box-shadow var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-inner {
max-width: 1280px;
margin: 0 auto;
height: 100%;
display: flex;
align-items: center;
padding: 0 2rem;
gap: 2rem;
}
.nb-drk .brand {
text-decoration: none;
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.nb-drk .brand-mark {
width: 28px;
height: 28px;
border-radius: 7px;
background: var(--nb-drk-accent);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .brand-mark svg {
display: block;
}
.nb-drk .brand-name {
font-size: 1rem;
font-weight: 700;
letter-spacing: -0.02em;
color: var(--nb-drk-text);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .brand-tag {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
font-weight: 300;
color: var(--nb-drk-text-3);
letter-spacing: 0.04em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-links {
display: flex;
align-items: center;
gap: 0;
list-style: none;
flex: 1;
}
.nb-drk .nav-links a {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.8rem;
font-weight: 500;
color: var(--nb-drk-text-2);
text-decoration: none;
padding: 7px 13px;
border-radius: 8px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), background 0.18s var(--nb-drk-ease);
white-space: nowrap;
}
.nb-drk .nav-links a:hover {
color: var(--nb-drk-text);
background: var(--nb-drk-border-soft);
}
.nb-drk .nav-links a.active {
color: var(--nb-drk-text);
background: var(--nb-drk-accent-bg);
}
.nb-drk .nav-links a.active .link-dot {
background: var(--nb-drk-accent);
}
.nb-drk .link-dot {
width: 5px;
height: 5px;
border-radius: 50%;
background: transparent;
flex-shrink: 0;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-spacer {
flex: 1;
}
.nb-drk .nav-actions {
display: flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
}
.nb-drk .theme-toggle {
display: flex;
align-items: center;
gap: 9px;
background: none;
border: none;
cursor: pointer;
padding: 6px 10px;
border-radius: 10px;
transition: background 0.18s;
font-family: inherit;
color: inherit;
}
.nb-drk .theme-toggle:hover {
background: var(--nb-drk-border-soft);
}
.nb-drk .toggle-track {
width: 36px;
height: 20px;
border-radius: 100px;
background: var(--nb-drk-toggle-track);
border: 1.5px solid var(--nb-drk-border);
position: relative;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
flex-shrink: 0;
}
.nb-drk .toggle-thumb {
position: absolute;
top: 2px;
left: 2px;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--nb-drk-toggle-thumb);
transition: transform var(--nb-drk-dur) cubic-bezier(0.34, 1.56, 0.64, 1), background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk[data-theme="dark"] .toggle-thumb {
transform: translateX(16px);
}
.nb-drk .icon-sun,
.nb-drk .icon-moon {
width: 14px;
height: 14px;
transition: opacity 0.3s var(--nb-drk-ease), transform 0.4s var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
color: var(--nb-drk-text-2);
}
.nb-drk[data-theme="light"] .icon-sun {
opacity: 1;
transform: rotate(0deg);
}
.nb-drk[data-theme="light"] .icon-moon {
opacity: 0.3;
}
.nb-drk[data-theme="dark"] .icon-moon {
opacity: 1;
transform: rotate(-15deg);
}
.nb-drk[data-theme="dark"] .icon-sun {
opacity: 0.3;
}
.nb-drk .toggle-label {
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
color: var(--nb-drk-text-3);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
white-space: nowrap;
}
.nb-drk .nav-div {
width: 1px;
height: 20px;
background: var(--nb-drk-border);
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .btn-ghost {
font-family: 'Epilogue', sans-serif;
font-size: 0.78rem;
font-weight: 500;
color: var(--nb-drk-text-2);
background: none;
border: 1px solid var(--nb-drk-border);
border-radius: 8px;
padding: 7px 15px;
cursor: pointer;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), background 0.18s;
white-space: nowrap;
}
.nb-drk .btn-ghost:hover {
color: var(--nb-drk-text);
border-color: var(--nb-drk-text-3);
}
.nb-drk .btn-fill {
font-family: 'Epilogue', sans-serif;
font-size: 0.78rem;
font-weight: 700;
color: var(--nb-drk-invert-text);
background: var(--nb-drk-text);
border: none;
border-radius: 8px;
padding: 7px 16px;
cursor: pointer;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease), transform 0.15s;
white-space: nowrap;
}
.nb-drk .btn-fill:hover {
transform: translateY(-1px);
}
.nb-drk .page {
padding-top: 64px;
}
.nb-drk .hero {
min-height: 560px;
display: grid;
grid-template-columns: 1fr 1fr;
}
.nb-drk .hero-left {
padding: 5rem 4rem;
display: flex;
flex-direction: column;
justify-content: center;
border-right: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-pill {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
font-weight: 400;
color: var(--nb-drk-accent);
background: var(--nb-drk-accent-bg);
border: 1px solid rgba(232,74,47,0.15);
border-radius: 100px;
padding: 5px 12px;
margin-bottom: 2rem;
width: fit-content;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-pill::before {
content: '◉';
font-size: 0.55rem;
}
.nb-drk h1 {
font-size: clamp(2.8rem, 4.5vw, 5rem);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 1.0;
color: var(--nb-drk-text);
margin-bottom: 1.5rem;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk h1 em {
font-style: italic;
font-weight: 300;
color: var(--nb-drk-accent);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-body {
font-size: 1rem;
color: var(--nb-drk-text-2);
line-height: 1.7;
max-width: 42ch;
margin-bottom: 2.5rem;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-ctas {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
}
.nb-drk .cta-main {
font-family: 'Epilogue', sans-serif;
font-size: 0.82rem;
font-weight: 700;
color: var(--nb-drk-invert-text);
background: var(--nb-drk-text);
border: none;
border-radius: 10px;
padding: 12px 22px;
cursor: pointer;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease), transform 0.15s;
}
.nb-drk .cta-main:hover {
transform: translateY(-2px);
}
.nb-drk .cta-link {
font-size: 0.82rem;
font-weight: 500;
color: var(--nb-drk-text-2);
text-decoration: none;
transition: color 0.2s;
display: flex;
align-items: center;
gap: 6px;
}
.nb-drk .cta-link:hover {
color: var(--nb-drk-text);
}
.nb-drk .hero-right {
padding: 3rem;
display: flex;
align-items: center;
justify-content: center;
background: var(--nb-drk-bg-2);
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .preview-panel {
width: 100%;
max-width: 400px;
display: flex;
flex-direction: column;
gap: 12px;
}
.nb-drk .preview-label {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--nb-drk-text-3);
margin-bottom: 4px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .token-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-bottom: 4px;
}
.nb-drk .token-card {
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
padding: 12px 14px;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), box-shadow var(--nb-drk-dur) var(--nb-drk-ease);
box-shadow: var(--nb-drk-shadow-card);
}
.nb-drk .token-swatch {
width: 20px;
height: 20px;
border-radius: 5px;
margin-bottom: 8px;
border: 1px solid var(--nb-drk-border-soft);
}
.nb-drk .token-name {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
color: var(--nb-drk-text-3);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
margin-bottom: 2px;
}
.nb-drk .token-val {
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
color: var(--nb-drk-text);
font-weight: 500;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .code-block {
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
padding: 14px 16px;
font-family: 'Fira Code', monospace;
font-size: 0.68rem;
line-height: 1.8;
color: var(--nb-drk-text-2);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
box-shadow: var(--nb-drk-shadow-card);
}
.nb-drk .code-attr {
color: var(--nb-drk-accent);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .code-val {
color: var(--nb-drk-text);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-strip {
display: flex;
gap: 0;
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
overflow: hidden;
box-shadow: var(--nb-drk-shadow-card);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-item {
flex: 1;
padding: 12px 14px;
border-right: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-item:last-child {
border-right: none;
}
.nb-drk .stat-val {
font-size: 1.2rem;
font-weight: 900;
letter-spacing: -0.03em;
color: var(--nb-drk-text);
line-height: 1;
margin-bottom: 3px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-lbl {
font-size: 0.62rem;
color: var(--nb-drk-text-3);
font-weight: 500;
letter-spacing: 0.04em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .theme-flash {
position: absolute;
inset: 0;
z-index: 99;
pointer-events: none;
opacity: 0;
border-radius: 50%;
transform: scale(0);
}
.nb-drk .theme-flash.animate {
animation: nb-drk-ripple 0.55s ease-out forwards;
}
@keyframes nb-drk-ripple {
0% {
opacity: 0.12;
transform: scale(0);
border-radius: 50%;
}
60% {
opacity: 0.06;
transform: scale(3);
}
100% {
opacity: 0;
transform: scale(5);
}
}
.nb-drk .features {
display: grid;
grid-template-columns: repeat(4, 1fr);
border-top: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature {
padding: 2.5rem 2rem;
border-right: 1px solid var(--nb-drk-border);
transition: background 0.2s, border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature:last-child {
border-right: none;
}
.nb-drk .feature:hover {
background: var(--nb-drk-bg-2);
}
.nb-drk .feature-icon {
width: 36px;
height: 36px;
border-radius: 9px;
background: var(--nb-drk-accent-bg);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1rem;
color: var(--nb-drk-accent);
font-size: 1rem;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature-title {
font-size: 0.88rem;
font-weight: 700;
color: var(--nb-drk-text);
margin-bottom: 0.4rem;
letter-spacing: -0.01em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature-desc {
font-size: 0.78rem;
color: var(--nb-drk-text-2);
line-height: 1.6;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
@media (max-width: 900px) {
.nb-drk .hero {
grid-template-columns: 1fr;
}
.nb-drk .hero-left {
border-right: none;
border-bottom: 1px solid var(--nb-drk-border);
padding: 3rem 2rem;
}
.nb-drk .hero-right {
padding: 2rem;
}
.nb-drk .features {
grid-template-columns: 1fr 1fr;
}
.nb-drk .feature:nth-child(2) {
border-right: none;
}
.nb-drk .feature:nth-child(3),
.nb-drk .feature:nth-child(4) {
border-top: 1px solid var(--nb-drk-border);
}
.nb-drk .nav-links {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.nb-drk *,
.nb-drk *::before,
.nb-drk *::after {
transition: none !important;
animation: none !important;
}
}
```
## JavaScript
```js
(() => {
// Scoped dark-mode toggle. Theme attribute lives on the wrapper, not
// <html>, so multiple instances on a page each carry their own theme
// state. The source mock used localStorage + prefers-color-scheme —
// both dropped because the embedded demo doesn't own the host page's
// theme preference. The radial flash overlay is bounded to the
// wrapper (position:absolute) so it doesn't escape into the gallery.
const root = document.querySelector('.nb-drk');
if (!root) return;
const toggle = root.querySelector('[data-nb-drk-toggle]');
const label = root.querySelector('[data-nb-drk-label]');
const flash = root.querySelector('[data-nb-drk-flash]');
if (!toggle || !label || !flash) return;
const tokens = {
light: { bg: '#fafaf8', text: '#18181a', accent: '#e84a2f', border: '#e4e2dc', surface: '#ffffff' },
dark: { bg: '#111113', text: '#f0efec', accent: '#ff6b4a', border: '#2e2e34', surface: '#1e1e22' },
};
function updatePreview(theme) {
const t = tokens[theme];
for (const key of ['bg', 'text', 'accent', 'border']) {
const valEl = root.querySelector('[data-nb-drk-val="' + key + '"]');
const swatchEl = root.querySelector('[data-nb-drk-swatch="' + key + '"]');
if (valEl) valEl.textContent = t[key];
if (swatchEl) swatchEl.style.background = t[key];
}
for (const key of ['bg', 'text', 'accent', 'surface']) {
const codeEl = root.querySelector('[data-nb-drk-code="' + key + '"]');
if (codeEl) codeEl.textContent = t[key];
}
const themeInCode = root.querySelector('[data-nb-drk-theme-in-code]');
if (themeInCode) themeInCode.textContent = theme;
label.textContent = theme === 'dark' ? 'Dark' : 'Light';
}
function triggerFlash(theme) {
flash.style.background = theme === 'dark' ? '#f0efec' : '#111113';
flash.classList.remove('animate');
// Force reflow so the animation restarts.
void flash.offsetWidth;
flash.classList.add('animate');
}
function applyTheme(theme) {
root.setAttribute('data-theme', theme);
updatePreview(theme);
}
// Seed from the wrapper's current data-theme (default "light" via HTML).
applyTheme(root.getAttribute('data-theme') || 'light');
toggle.addEventListener('click', () => {
const next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
triggerFlash(next);
applyTheme(next);
});
})();
```Here's a working CSS Navbar Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Navbar with Dark Mode Toggle
Source: https://codefronts.com/navigation/css-navbars/css-navbar-with-dark-mode-toggle/
A CSS navbar with a built-in dark mode toggle that flips the entire UI in under half a second — proving that semantic design tokens beat a `prefers-color-scheme` media query when you want users to control the theme themselves. The frosted backdrop-filter navbar carries a Linea wordmark + version chip, 5 active-dot nav links (Overview / Components / Templates / Docs / Changelog), and a custom track-and-thumb theme toggle that transitions between sun and moon icons with a 0.45s ease. Click triggers a radial flash overlay that ripples outward as the body recolors. Below the navbar: a hero with a live token preview panel (4 swatch cards for `--bg`, `--text`, `--accent`, `--border` updating their hex values in real time) + a `[data-theme]` CSS code block that re-renders + a stats strip (48 Tokens / 2 Themes / 0.45s Transition). Bottom features grid covers semantic-token theming, CSS-only transitions, WCAG AA contrast, and `localStorage` persistence. Epilogue + Fira Code. Best for design system docs, developer tool sites, modern SaaS landing pages, theme-toggle component galleries.
## HTML
```html
<section class="nb-drk" data-theme="light" aria-label="CSS navbar with dark mode toggle demo">
<div class="theme-flash" data-nb-drk-flash aria-hidden="true"></div>
<nav aria-label="Primary">
<div class="nav-inner">
<a href="#" class="brand">
<div class="brand-mark">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" aria-hidden="true"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
</div>
<div>
<div class="brand-name">Linea</div>
<div class="brand-tag">v3.2.0</div>
</div>
</a>
<ul class="nav-links">
<li><a href="#" class="active"><span class="link-dot"></span>Overview</a></li>
<li><a href="#"><span class="link-dot"></span>Components</a></li>
<li><a href="#"><span class="link-dot"></span>Templates</a></li>
<li><a href="#"><span class="link-dot"></span>Docs</a></li>
<li><a href="#"><span class="link-dot"></span>Changelog</a></li>
</ul>
<div class="nav-spacer"></div>
<div class="nav-actions">
<button class="theme-toggle" type="button" data-nb-drk-toggle aria-label="Toggle dark mode">
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
<div class="toggle-track"><div class="toggle-thumb"></div></div>
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
<span class="toggle-label" data-nb-drk-label>Light</span>
</button>
<div class="nav-div" aria-hidden="true"></div>
<button class="btn-ghost" type="button">Sign in</button>
<button class="btn-fill" type="button">Get started</button>
</div>
</div>
</nav>
<div class="page">
<section class="hero">
<div class="hero-left">
<div class="hero-pill">Now in v3 — See what's new</div>
<h1>Design tokens<br>that <em>adapt</em><br>with you.</h1>
<p class="hero-body">Every color, shadow, and surface in this UI is driven by semantic CSS custom properties. Watch them all flip in under half a second — click the toggle above.</p>
<div class="hero-ctas">
<button class="cta-main" type="button">Browse Components →</button>
<a href="#" class="cta-link">
View on GitHub
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
</a>
</div>
</div>
<div class="hero-right">
<div class="preview-panel">
<p class="preview-label">Live token preview — toggle the theme above</p>
<div class="token-grid">
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="bg"></div>
<div class="token-name">--bg</div>
<div class="token-val" data-nb-drk-val="bg">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="text"></div>
<div class="token-name">--text</div>
<div class="token-val" data-nb-drk-val="text">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="accent"></div>
<div class="token-name">--accent</div>
<div class="token-val" data-nb-drk-val="accent">—</div>
</div>
<div class="token-card">
<div class="token-swatch" data-nb-drk-swatch="border"></div>
<div class="token-name">--border</div>
<div class="token-val" data-nb-drk-val="border">—</div>
</div>
</div>
<div class="code-block">
<span class="code-attr">[data-theme=<span class="code-val">"<span data-nb-drk-theme-in-code>light</span>"</span>]</span> {<br>
<span class="code-attr">--bg</span>: <span class="code-val" data-nb-drk-code="bg">#fafaf8</span>;<br>
<span class="code-attr">--text</span>: <span class="code-val" data-nb-drk-code="text">#18181a</span>;<br>
<span class="code-attr">--accent</span>: <span class="code-val" data-nb-drk-code="accent">#e84a2f</span>;<br>
<span class="code-attr">--surface</span>: <span class="code-val" data-nb-drk-code="surface">#ffffff</span>;<br>
}
</div>
<div class="stat-strip">
<div class="stat-item"><div class="stat-val">48</div><div class="stat-lbl">Tokens</div></div>
<div class="stat-item"><div class="stat-val">2</div><div class="stat-lbl">Themes</div></div>
<div class="stat-item"><div class="stat-val">0.45s</div><div class="stat-lbl">Transition</div></div>
</div>
</div>
</div>
</section>
<div class="features">
<div class="feature">
<div class="feature-icon">◑</div>
<div class="feature-title">Semantic tokens</div>
<div class="feature-desc">Every value maps to intent, not raw colors. Theme by switching a single attribute.</div>
</div>
<div class="feature">
<div class="feature-icon">⚡</div>
<div class="feature-title">CSS-only transitions</div>
<div class="feature-desc">No JavaScript required for the color shift. Pure CSS custom properties do the work.</div>
</div>
<div class="feature">
<div class="feature-icon">♿</div>
<div class="feature-title">WCAG AA+</div>
<div class="feature-desc">Both themes pass contrast requirements for text, borders, and interactive states.</div>
</div>
<div class="feature">
<div class="feature-icon">💾</div>
<div class="feature-title">Persisted preference</div>
<div class="feature-desc">Choice is saved to localStorage and respects prefers-color-scheme on first load.</div>
</div>
</div>
</div>
</section>
```
## CSS
```css
/* ─── 07 Linea — CSS navbar with dark mode toggle UI ──────────── */
@import url('https://fonts.googleapis.com/css2?family=Epilogue:ital,wght@0,300;0,400;0,500;0,700;0,900;1,300;1,700&family=Fira+Code:wght@300;400;500&display=swap');
.nb-drk {
--nb-drk-ease: cubic-bezier(0.4, 0, 0.2, 1);
--nb-drk-dur: 0.45s;
position: relative;
width: 100%;
min-height: 720px;
font-family: 'Epilogue', sans-serif;
overflow: hidden;
box-sizing: border-box;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk *,
.nb-drk *::before,
.nb-drk *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.nb-drk[data-theme="light"] {
--nb-drk-bg: #fafaf8;
--nb-drk-bg-2: #f2f1ee;
--nb-drk-surface: #ffffff;
--nb-drk-surface-float: rgba(255,255,255,0.85);
--nb-drk-border: #e4e2dc;
--nb-drk-border-soft: rgba(0,0,0,0.06);
--nb-drk-text: #18181a;
--nb-drk-text-2: #5a5856;
--nb-drk-text-3: #a09e99;
--nb-drk-accent: #e84a2f;
--nb-drk-accent-bg: rgba(232,74,47,0.08);
--nb-drk-toggle-track: #e4e2dc;
--nb-drk-toggle-thumb: #18181a;
--nb-drk-shadow-nav: 0 1px 0 var(--nb-drk-border), 0 4px 24px rgba(0,0,0,0.05);
--nb-drk-shadow-card: 0 2px 16px rgba(0,0,0,0.07);
--nb-drk-invert-text: #fafaf8;
}
.nb-drk[data-theme="dark"] {
--nb-drk-bg: #111113;
--nb-drk-bg-2: #19191c;
--nb-drk-surface: #1e1e22;
--nb-drk-surface-float: rgba(22,22,26,0.88);
--nb-drk-border: #2e2e34;
--nb-drk-border-soft: rgba(255,255,255,0.06);
--nb-drk-text: #f0efec;
--nb-drk-text-2: #9e9c97;
--nb-drk-text-3: #5c5a57;
--nb-drk-accent: #ff6b4a;
--nb-drk-accent-bg: rgba(255,107,74,0.1);
--nb-drk-toggle-track: #2e2e34;
--nb-drk-toggle-thumb: #f0efec;
--nb-drk-shadow-nav: 0 1px 0 var(--nb-drk-border), 0 4px 32px rgba(0,0,0,0.3);
--nb-drk-shadow-card: 0 2px 20px rgba(0,0,0,0.3);
--nb-drk-invert-text: #111113;
}
.nb-drk {
background: var(--nb-drk-bg);
color: var(--nb-drk-text);
}
.nb-drk nav {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 100;
height: 64px;
background: var(--nb-drk-surface-float);
backdrop-filter: blur(20px) saturate(150%);
-webkit-backdrop-filter: blur(20px) saturate(150%);
border-bottom: 1px solid var(--nb-drk-border);
box-shadow: var(--nb-drk-shadow-nav);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), box-shadow var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-inner {
max-width: 1280px;
margin: 0 auto;
height: 100%;
display: flex;
align-items: center;
padding: 0 2rem;
gap: 2rem;
}
.nb-drk .brand {
text-decoration: none;
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.nb-drk .brand-mark {
width: 28px;
height: 28px;
border-radius: 7px;
background: var(--nb-drk-accent);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .brand-mark svg {
display: block;
}
.nb-drk .brand-name {
font-size: 1rem;
font-weight: 700;
letter-spacing: -0.02em;
color: var(--nb-drk-text);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .brand-tag {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
font-weight: 300;
color: var(--nb-drk-text-3);
letter-spacing: 0.04em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-links {
display: flex;
align-items: center;
gap: 0;
list-style: none;
flex: 1;
}
.nb-drk .nav-links a {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.8rem;
font-weight: 500;
color: var(--nb-drk-text-2);
text-decoration: none;
padding: 7px 13px;
border-radius: 8px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), background 0.18s var(--nb-drk-ease);
white-space: nowrap;
}
.nb-drk .nav-links a:hover {
color: var(--nb-drk-text);
background: var(--nb-drk-border-soft);
}
.nb-drk .nav-links a.active {
color: var(--nb-drk-text);
background: var(--nb-drk-accent-bg);
}
.nb-drk .nav-links a.active .link-dot {
background: var(--nb-drk-accent);
}
.nb-drk .link-dot {
width: 5px;
height: 5px;
border-radius: 50%;
background: transparent;
flex-shrink: 0;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .nav-spacer {
flex: 1;
}
.nb-drk .nav-actions {
display: flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
}
.nb-drk .theme-toggle {
display: flex;
align-items: center;
gap: 9px;
background: none;
border: none;
cursor: pointer;
padding: 6px 10px;
border-radius: 10px;
transition: background 0.18s;
font-family: inherit;
color: inherit;
}
.nb-drk .theme-toggle:hover {
background: var(--nb-drk-border-soft);
}
.nb-drk .toggle-track {
width: 36px;
height: 20px;
border-radius: 100px;
background: var(--nb-drk-toggle-track);
border: 1.5px solid var(--nb-drk-border);
position: relative;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
flex-shrink: 0;
}
.nb-drk .toggle-thumb {
position: absolute;
top: 2px;
left: 2px;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--nb-drk-toggle-thumb);
transition: transform var(--nb-drk-dur) cubic-bezier(0.34, 1.56, 0.64, 1), background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk[data-theme="dark"] .toggle-thumb {
transform: translateX(16px);
}
.nb-drk .icon-sun,
.nb-drk .icon-moon {
width: 14px;
height: 14px;
transition: opacity 0.3s var(--nb-drk-ease), transform 0.4s var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
color: var(--nb-drk-text-2);
}
.nb-drk[data-theme="light"] .icon-sun {
opacity: 1;
transform: rotate(0deg);
}
.nb-drk[data-theme="light"] .icon-moon {
opacity: 0.3;
}
.nb-drk[data-theme="dark"] .icon-moon {
opacity: 1;
transform: rotate(-15deg);
}
.nb-drk[data-theme="dark"] .icon-sun {
opacity: 0.3;
}
.nb-drk .toggle-label {
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
color: var(--nb-drk-text-3);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
white-space: nowrap;
}
.nb-drk .nav-div {
width: 1px;
height: 20px;
background: var(--nb-drk-border);
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .btn-ghost {
font-family: 'Epilogue', sans-serif;
font-size: 0.78rem;
font-weight: 500;
color: var(--nb-drk-text-2);
background: none;
border: 1px solid var(--nb-drk-border);
border-radius: 8px;
padding: 7px 15px;
cursor: pointer;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), background 0.18s;
white-space: nowrap;
}
.nb-drk .btn-ghost:hover {
color: var(--nb-drk-text);
border-color: var(--nb-drk-text-3);
}
.nb-drk .btn-fill {
font-family: 'Epilogue', sans-serif;
font-size: 0.78rem;
font-weight: 700;
color: var(--nb-drk-invert-text);
background: var(--nb-drk-text);
border: none;
border-radius: 8px;
padding: 7px 16px;
cursor: pointer;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease), transform 0.15s;
white-space: nowrap;
}
.nb-drk .btn-fill:hover {
transform: translateY(-1px);
}
.nb-drk .page {
padding-top: 64px;
}
.nb-drk .hero {
min-height: 560px;
display: grid;
grid-template-columns: 1fr 1fr;
}
.nb-drk .hero-left {
padding: 5rem 4rem;
display: flex;
flex-direction: column;
justify-content: center;
border-right: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-pill {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
font-weight: 400;
color: var(--nb-drk-accent);
background: var(--nb-drk-accent-bg);
border: 1px solid rgba(232,74,47,0.15);
border-radius: 100px;
padding: 5px 12px;
margin-bottom: 2rem;
width: fit-content;
transition: color var(--nb-drk-dur) var(--nb-drk-ease), background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-pill::before {
content: '◉';
font-size: 0.55rem;
}
.nb-drk h1 {
font-size: clamp(2.8rem, 4.5vw, 5rem);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 1.0;
color: var(--nb-drk-text);
margin-bottom: 1.5rem;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk h1 em {
font-style: italic;
font-weight: 300;
color: var(--nb-drk-accent);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-body {
font-size: 1rem;
color: var(--nb-drk-text-2);
line-height: 1.7;
max-width: 42ch;
margin-bottom: 2.5rem;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .hero-ctas {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
}
.nb-drk .cta-main {
font-family: 'Epilogue', sans-serif;
font-size: 0.82rem;
font-weight: 700;
color: var(--nb-drk-invert-text);
background: var(--nb-drk-text);
border: none;
border-radius: 10px;
padding: 12px 22px;
cursor: pointer;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease), transform 0.15s;
}
.nb-drk .cta-main:hover {
transform: translateY(-2px);
}
.nb-drk .cta-link {
font-size: 0.82rem;
font-weight: 500;
color: var(--nb-drk-text-2);
text-decoration: none;
transition: color 0.2s;
display: flex;
align-items: center;
gap: 6px;
}
.nb-drk .cta-link:hover {
color: var(--nb-drk-text);
}
.nb-drk .hero-right {
padding: 3rem;
display: flex;
align-items: center;
justify-content: center;
background: var(--nb-drk-bg-2);
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .preview-panel {
width: 100%;
max-width: 400px;
display: flex;
flex-direction: column;
gap: 12px;
}
.nb-drk .preview-label {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--nb-drk-text-3);
margin-bottom: 4px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .token-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-bottom: 4px;
}
.nb-drk .token-card {
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
padding: 12px 14px;
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), box-shadow var(--nb-drk-dur) var(--nb-drk-ease);
box-shadow: var(--nb-drk-shadow-card);
}
.nb-drk .token-swatch {
width: 20px;
height: 20px;
border-radius: 5px;
margin-bottom: 8px;
border: 1px solid var(--nb-drk-border-soft);
}
.nb-drk .token-name {
font-family: 'Fira Code', monospace;
font-size: 0.6rem;
color: var(--nb-drk-text-3);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
margin-bottom: 2px;
}
.nb-drk .token-val {
font-family: 'Fira Code', monospace;
font-size: 0.65rem;
color: var(--nb-drk-text);
font-weight: 500;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .code-block {
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
padding: 14px 16px;
font-family: 'Fira Code', monospace;
font-size: 0.68rem;
line-height: 1.8;
color: var(--nb-drk-text-2);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease), color var(--nb-drk-dur) var(--nb-drk-ease);
box-shadow: var(--nb-drk-shadow-card);
}
.nb-drk .code-attr {
color: var(--nb-drk-accent);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .code-val {
color: var(--nb-drk-text);
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-strip {
display: flex;
gap: 0;
background: var(--nb-drk-surface);
border: 1px solid var(--nb-drk-border);
border-radius: 10px;
overflow: hidden;
box-shadow: var(--nb-drk-shadow-card);
transition: background var(--nb-drk-dur) var(--nb-drk-ease), border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-item {
flex: 1;
padding: 12px 14px;
border-right: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-item:last-child {
border-right: none;
}
.nb-drk .stat-val {
font-size: 1.2rem;
font-weight: 900;
letter-spacing: -0.03em;
color: var(--nb-drk-text);
line-height: 1;
margin-bottom: 3px;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .stat-lbl {
font-size: 0.62rem;
color: var(--nb-drk-text-3);
font-weight: 500;
letter-spacing: 0.04em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .theme-flash {
position: absolute;
inset: 0;
z-index: 99;
pointer-events: none;
opacity: 0;
border-radius: 50%;
transform: scale(0);
}
.nb-drk .theme-flash.animate {
animation: nb-drk-ripple 0.55s ease-out forwards;
}
@keyframes nb-drk-ripple {
0% {
opacity: 0.12;
transform: scale(0);
border-radius: 50%;
}
60% {
opacity: 0.06;
transform: scale(3);
}
100% {
opacity: 0;
transform: scale(5);
}
}
.nb-drk .features {
display: grid;
grid-template-columns: repeat(4, 1fr);
border-top: 1px solid var(--nb-drk-border);
transition: border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature {
padding: 2.5rem 2rem;
border-right: 1px solid var(--nb-drk-border);
transition: background 0.2s, border-color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature:last-child {
border-right: none;
}
.nb-drk .feature:hover {
background: var(--nb-drk-bg-2);
}
.nb-drk .feature-icon {
width: 36px;
height: 36px;
border-radius: 9px;
background: var(--nb-drk-accent-bg);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1rem;
color: var(--nb-drk-accent);
font-size: 1rem;
transition: background var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature-title {
font-size: 0.88rem;
font-weight: 700;
color: var(--nb-drk-text);
margin-bottom: 0.4rem;
letter-spacing: -0.01em;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
.nb-drk .feature-desc {
font-size: 0.78rem;
color: var(--nb-drk-text-2);
line-height: 1.6;
transition: color var(--nb-drk-dur) var(--nb-drk-ease);
}
@media (max-width: 900px) {
.nb-drk .hero {
grid-template-columns: 1fr;
}
.nb-drk .hero-left {
border-right: none;
border-bottom: 1px solid var(--nb-drk-border);
padding: 3rem 2rem;
}
.nb-drk .hero-right {
padding: 2rem;
}
.nb-drk .features {
grid-template-columns: 1fr 1fr;
}
.nb-drk .feature:nth-child(2) {
border-right: none;
}
.nb-drk .feature:nth-child(3),
.nb-drk .feature:nth-child(4) {
border-top: 1px solid var(--nb-drk-border);
}
.nb-drk .nav-links {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.nb-drk *,
.nb-drk *::before,
.nb-drk *::after {
transition: none !important;
animation: none !important;
}
}
```
## JavaScript
```js
(() => {
// Scoped dark-mode toggle. Theme attribute lives on the wrapper, not
// <html>, so multiple instances on a page each carry their own theme
// state. The source mock used localStorage + prefers-color-scheme —
// both dropped because the embedded demo doesn't own the host page's
// theme preference. The radial flash overlay is bounded to the
// wrapper (position:absolute) so it doesn't escape into the gallery.
const root = document.querySelector('.nb-drk');
if (!root) return;
const toggle = root.querySelector('[data-nb-drk-toggle]');
const label = root.querySelector('[data-nb-drk-label]');
const flash = root.querySelector('[data-nb-drk-flash]');
if (!toggle || !label || !flash) return;
const tokens = {
light: { bg: '#fafaf8', text: '#18181a', accent: '#e84a2f', border: '#e4e2dc', surface: '#ffffff' },
dark: { bg: '#111113', text: '#f0efec', accent: '#ff6b4a', border: '#2e2e34', surface: '#1e1e22' },
};
function updatePreview(theme) {
const t = tokens[theme];
for (const key of ['bg', 'text', 'accent', 'border']) {
const valEl = root.querySelector('[data-nb-drk-val="' + key + '"]');
const swatchEl = root.querySelector('[data-nb-drk-swatch="' + key + '"]');
if (valEl) valEl.textContent = t[key];
if (swatchEl) swatchEl.style.background = t[key];
}
for (const key of ['bg', 'text', 'accent', 'surface']) {
const codeEl = root.querySelector('[data-nb-drk-code="' + key + '"]');
if (codeEl) codeEl.textContent = t[key];
}
const themeInCode = root.querySelector('[data-nb-drk-theme-in-code]');
if (themeInCode) themeInCode.textContent = theme;
label.textContent = theme === 'dark' ? 'Dark' : 'Light';
}
function triggerFlash(theme) {
flash.style.background = theme === 'dark' ? '#f0efec' : '#111113';
flash.classList.remove('animate');
// Force reflow so the animation restarts.
void flash.offsetWidth;
flash.classList.add('animate');
}
function applyTheme(theme) {
root.setAttribute('data-theme', theme);
updatePreview(theme);
}
// Seed from the wrapper's current data-theme (default "light" via HTML).
applyTheme(root.getAttribute('data-theme') || 'light');
toggle.addEventListener('click', () => {
const next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
triggerFlash(next);
applyTheme(next);
});
})();
```