Skip to main content
Version: Next

Theme Rules

Dark mode is the primary experience

colorMode: {
defaultMode: 'dark',
respectPrefersColorScheme: false,
}

Every new visitor sees dark mode by default, regardless of their OS color-scheme preference — this is a deliberate choice, not the Docusaurus default (which would otherwise respect system preference over the configured default). Light mode remains fully supported via the manual toggle in the navbar, and uses the exact same brand tokens, only with inverted neutral surfaces (see Colors).

Accessibility

Contrast requirement: WCAG AA — 4.5:1 for normal text, 3:1 for large text (≥18pt / ≥14pt bold) and meaningful UI element boundaries. Full computed table:

PairingRatioAA-normal (4.5)AA-large/UI (3.0)
White text on Dark Background18.92PASSPASS
White text on Surface16.41PASSPASS
Secondary text on Dark Background7.77PASSPASS
Secondary text on Surface6.74PASSPASS
Primary Blue on Dark Background4.58PASSPASS
Primary Blue on Surface3.97FAILPASS
Primary Teal on Dark Background7.16PASSPASS
Primary Teal on Surface6.21PASSPASS
White text on Blue-text shade (#0065D8)5.45PASSPASS
White text on Teal-text shade (#007D6F)5.04PASSPASS
Dark ink on White (light mode)18.92PASSPASS
Blue-text shade on White (light mode links)5.45PASSPASS

The one row that stays a controlled exception — "Primary Blue on Surface" at 3.97 — is only ever used for large/decorative elements (icons, borders, large badges), never for body-sized text, which is why the AA-large/UI 3.0 threshold (not 4.5) is the one that applies there.

Keyboard navigation & focus: every interactive element (a, button, [tabindex], input) gets a visible 2px solid var(--shumoul-blue) focus ring with 2px offset on :focus-visible — a consistent, on-brand replacement for the browser's default focus outline, never removed without a replacement.

Reduced motion: @media (prefers-reduced-motion: reduce) collapses every animation/transition duration to near-zero site-wide.

Motion

Subtle only — see Spacing § Motion tokens. Two transition speeds exist site-wide (120ms for color/background changes, 200ms for larger movement like card lift-on-hover); nothing animates on page load, and no auto-playing motion exists anywhere.

Code block syntax colors are exempt

The two-hue-only rule governs UI chrome — navbar, buttons, badges, admonitions, links. It does not extend to code syntax highlighting, which functionally requires multiple distinguishable hues to differentiate keywords, strings, comments, and identifiers — this is a readability concern, not a branding one, and no reasonable brand system extends strict UI-chrome color rules into syntax highlighting. vsDark/vsLight (from prism-react-renderer) were chosen specifically because their background/chrome is neutral, not because their token colors are restricted to blue/teal.

Performance

No new JavaScript libraries were added — every visual change is CSS plus configuration (docusaurus.config.js) plus static assets (SVG logo variants, 3 self-hosted WOFF2 font files, ~81KB total). Fonts use font-display: swap and are self-hosted specifically to avoid the extra DNS lookup, connection, and possible redirect that loading from fonts.googleapis.com at runtime would add to the critical rendering path — the single largest lever available for Lighthouse performance on a typography-heavy documentation site.

Extending this system

  1. Never hardcode a hex color, font name, spacing value, or border-radius in a component or page — add or reuse a token from custom.css first.
  2. Never introduce a third hue. If a new component seems to need a new color, it almost certainly needs a tint/shade of blue or teal instead — see how --shumoul-blue-soft / --shumoul-teal-soft (12% opacity tints) solve this for hover/active backgrounds without a new hue.
  3. Any new admonition-like or severity-coded UI must follow the same rule as Colors § Semantic mapping: teal for positive, blue for informational, and weight/icon (not hue) for severity.
  4. Re-run the contrast check in this page whenever a new text/background pairing is introduced — do not assume a pairing is safe because a similar one passed.