Light & Dark Preview

Light Mode

  • Bg: #f5f2eb (kraft paper)
  • Surface: #fdfcfa (warm white)
  • Text: #1a1a1a (warm black)
  • CRT scanlines: 0.06
  • CRT noise: 0.045

Dark Mode

  • Bg: #0f172a (deep slate)
  • Surface: #1e293b (dark slate)
  • Text: #e2e8f0 (light gray)
  • CRT scanlines: 0.12
  • CRT noise: 0.07

How It Works

  1. Auto-detect: Calculates sunrise/sunset for Saigon (lat 10.82, lon 106.63, UTC+7). If current time is between sunset and sunrise → dark mode.
  2. Manual toggle: Button in footer (☼/☾) with clock showing GMT+7 time. Overrides auto-detect.
  3. localStorage: Preference saved as kycuc-theme = "dark" | "light". Manual preference disables auto-switch.
  4. Periodic check: Every 5 minutes, re-calculates if no manual preference stored.
  5. Transition: background-color and color transition 0.3s ease for smooth switch.
  6. Tailwind tokens: 14 light-shade tokens (slate 50-200, orange 50-200, green 50-100, amber 50-100) overridden in [data-theme="dark"].
  7. Logo fix: SVG loaded via <img> cannot inherit currentColorfilter: invert(0.9) in dark mode.

CSS Pattern

:root[data-theme="dark"] {
  --bg-primary: #0f172a;
  --bg-surface: #1e293b;
  --text-primary: #e2e8f0;
  --accent-orange: var(--color-orange-400);
  /* ... all 40+ tokens override */
}

[data-theme="dark"] body::before {
  opacity: 0.12; /* CRT scanlines more visible */
}

[data-theme="dark"] .logo-mark {
  filter: invert(0.9); /* SVG loaded via img */
}

JS Pattern

// DarkModeToggle.astro (is:inline script)
function calcSunriseSunset(date) { /* astronomy math */ }
function isDarkNow() { /* compare with Saigon time */ }

// On load: localStorage ? manual : auto
// On toggle: flip data-theme + save pref
// Every 5min: re-check auto if no manual pref