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; }
} 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);
});
})();