Dark Mode

Light values sit on :root. Dark values apply through [data-color-scheme="dark"] and, when the page is not pinned, prefers-color-scheme: dark (see src/assets/scss/abstracts/_css-vars.scss).

Pin a page

Add one Nunjucks variable at the top of the page file:

{% set colorScheme = "dark" %}   {# or "light" #}

The layout writes data-color-scheme on <html>. A pinned attribute always wins over the saved preference and the OS setting. Every page shipped with Rasuke 1.0 currently pins "dark" (including 404); removing the line makes that page follow the visitor's system + saved choice.

Runtime toggle

public/assets/js/vendors/color-modes.js loads in <head> before first paint. It:

  • looks for [data-color-scheme-toggle] buttons (for example the offcanvas menu theme switch) and syncs aria-pressed + aria-label (data-label-to-light / data-label-to-dark);
  • persists the choice in localStorage under rasuke-color-scheme;
  • applies a stored choice on load without removing a scheme pinned by the page template;
  • adds the js class (and is-transition-in when the page transition will play) before the first frame, so nothing flashes;
  • if the page is not pinned and nothing is saved, follows prefers-color-scheme via CSS.
Write mode-safe CSS

Sections never reference a mode. Bind semantic tokens and they flip automatically:

.about-2 {
  background-color: var(--color-surface-subtle);
  color: var(--color-text-primary);
  border-color: var(--color-border-base);
}

Do not write a dark-only hex in SCSS. If a new color must differ by mode, add both light and dark values in tokens.json. The brand orange #FF6A3A, cream #FCF7F3, and footer surface #1B1B1B are intentionally identical in both modes.