6. CSS Customization

The Waterloo extension ships two stylesheets:

  • common_styles.css defines reusable CSS variables.

  • waterloo_base.css applies those variables to the generated Waterloo nodes.

This split is intentional. In most cases you should customize the variables in common_styles.css or override them in your own project stylesheet. Only change structural selectors from waterloo_base.css when you want to redesign layout, spacing, or diagnostics.

6.1. Tested Themes

The default styles are tested with the following Sphinx themes:

  • classic

  • alabaster

  • furo

The extension tries to stay theme-neutral, but themes differ in typography, spacing, dark-mode handling, and admonition styling. For that reason, the default CSS should be understood as a portable baseline rather than a finished visual identity for every possible theme.

6.2. common_styles.css

This stylesheet contains the shared visual vocabulary for Waterloo semantic markup. Each role can be adjusted through CSS variables for color, font weight, and font style.

The light-theme color variables are defined on :root:

	--wtrl-attr-color:#077;
	--wtrl-class-color:#770000;
	--wtrl-cmd-color:#996600;
	--wtrl-dfn-color:currentColor;
	--wtrl-file-color: #35f;
	--wtrl-func-color:#3040ff;
	--wtrl-key-color:currentColor;
	--wtrl-label-color:currentColor;
	--wtrl-lit-color:currentColor;
	--wtrl-mod-color:#462;
	--wtrl-norm-color:currentColor;
	--wtrl-op-color:currentColor;
	--wtrl-opt-color:currentColor;
	--wtrl-pkg-color:#252;
	--wtrl-tag-color:#900;
	--wtrl-term-color:currentColor;
	--wtrl-type-color:#770000;
	--wtrl-url-color: #35f;;
	--wtrl-value-color:#004400;
	--wtrl-var-color:#a00;

The naming pattern is:

  • --wtrl-<role>-color

  • --wtrl-<role>-font-weight

  • --wtrl-<role>-font-style

For dark mode, the stylesheet defines a second color set:

  • --wtrl-dark-<role>-color

The active role colors are then switched to the dark variables for themes that expose a dark-mode state. For furo, this state is stored on the document body:

body[data-theme="dark"] {
        --wtrl-attr-color:var(--wtrl-dark-attr-color);
        /* further role colors */
        }

The stylesheet also contains a media-query fallback for themes or browsers that use prefers-color-scheme. Additional theme-specific activation rules can be added later if another theme exposes dark mode differently.

If a role should keep the surrounding text color, use currentColor as the role color. This is usually preferable to hard-coding a theme color because it lets the active theme decide the foreground color.

6.3. waterloo_base.css

This stylesheet maps generated Waterloo nodes to concrete CSS classes. It forwards the role-related variables from common_styles.css into classes such as .wtrl_func, .wtrl_type, and .wtrl_var. It also defines layout-related styles for signatures, diagnostics, scope filtering, and unresolved references.

The following selectors are the most likely customization points.

6.3.1. Custom Admonitions

State-changing directives render custom admonitions when wtrl_state_change_admonitions_enabled is enabled. The extension does not actively style these admonitions beyond assigning semantic CSS classes. By default, their visual appearance is therefore inherited from the active Sphinx theme.

The generated admonitions carry one message class:

  • .wtrl-current-module-message

  • .wtrl-current-class-message

  • .wtrl-current-scope-message

and one direction class:

  • .wtrl-current-module-push

  • .wtrl-current-module-pop

  • .wtrl-current-class-push

  • .wtrl-current-class-pop

  • .wtrl-current-scope-push

  • .wtrl-current-scope-pop

This makes it possible to style all state-change messages uniformly or to distinguish module, class, and scope changes. For example:

.wtrl-current-module-message,
.wtrl-current-class-message,
.wtrl-current-scope-message {
        opacity:0.85;
        /* further shared admonition styling */
        }

.wtrl-current-scope-push {
        border-left-color:#6f42c1;
        /* further scope-push styling */
        }

6.3.2. Multiline Signatures

Multiline signatures are rendered as block elements. The outer block controls the frame, padding, and border radius:

div.wtrl-signature-multiline {
        border: solid 0.1em #cce;
        padding:0.5em;
        border-radius:0.3em;
        }

This is a good place to align the signature block with the active theme. For example, a theme with card-like elements might use a subtle shadow instead of a plain border.

Parameter lines are rendered inside the block. The font family is usually overridden by semantic roles inside the signature, so indentation is the more interesting property to customize:

div.wtrl-signature-param {
        font-family: monospace;
        padding-left: 3em;
        }

The closing line, including the return type annotation, uses a separate class:

div.wtrl-signature-ret {
        font-family: monospace;
        padding-left: 0em;
        }

When a multiline signature appears inside a rendered Waterloo documentation box, the surrounding section already provides visual structure. The nested signature block therefore drops its own frame:

.wtrl-section div.wtrl-signature-multiline {
        border: 0;
        padding: 0em;
        }

6.3.3. Normative Keywords

Normative keywords are marked with a small scales symbol:

.wtrl_norm::after
        {
        content: " \2696";
        font-weight:normal;
        font-style:normal;
        }

This is deliberately a matter of presentation, not semantics. The semantic information is already present in the generated node class. You can change the symbol, restyle it, or remove it entirely if it does not fit the surrounding documentation.

6.3.4. Out Of Scope

References to docstrings that are hidden by scope filtering are rendered with a muted style:

.wtrl_out_of_scope, .wtrl_out_of_scope *
        {
        color:#777 !important;
        opacity:0.85;
        }

This marker should not look like an error. The target exists, but it is not visible in the current documentation scope. A good redesign should communicate that the reference is intentionally unavailable under the active scope rules.