8 CSS Navbar Designs07 / 08

CSS + JSMIT licensed

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

Live Demo
Try it

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>
&nbsp;&nbsp;<span class="code-attr">--bg</span>: <span class="code-val" data-nb-drk-code="bg">#fafaf8</span>;<br>
&nbsp;&nbsp;<span class="code-attr">--text</span>: <span class="code-val" data-nb-drk-code="text">#18181a</span>;<br>
&nbsp;&nbsp;<span class="code-attr">--accent</span>: <span class="code-val" data-nb-drk-code="accent">#e84a2f</span>;<br>
&nbsp;&nbsp;<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;
  }
}
(() => {
  // 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);
  });
})();
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
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>
&nbsp;&nbsp;<span class="code-attr">--bg</span>: <span class="code-val" data-nb-drk-code="bg">#fafaf8</span>;<br>
&nbsp;&nbsp;<span class="code-attr">--text</span>: <span class="code-val" data-nb-drk-code="text">#18181a</span>;<br>
&nbsp;&nbsp;<span class="code-attr">--accent</span>: <span class="code-val" data-nb-drk-code="accent">#e84a2f</span>;<br>
&nbsp;&nbsp;<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);
  });
})();
```

Techniques used in this demo

Search CodeFronts

Loading…