Surfaces
Surfaces are decorative background treatments applied to <section> elements. They are registered as global CSS via Wage\Assets::register_global_css() and output as <style id="wage-global"> in the <head>.
How it works
Section titled “How it works”One surface = one class. Never stack two surface classes on the same element. Each surface is a single, self-contained CSS class defined in a paired CSS file. The child theme’s inc/surfaces/surfaces.php reads the CSS file and registers it with Wage\Assets::register_global_css(). There are two types:
- Simple surfaces — just set
backgroundon the element (gradients, solid colours) - Texture surfaces — add a
::afterpseudo-element for an SVG texture overlay, or use theWage\SectionBackgroundcomponent for image textures
Both use the same surface--{name} class in markup. No extra structural class needed.
Naming convention
Section titled “Naming convention”Surface classes are named by token role + texture: surface--primary-dark-engraving, surface--base-light-herringbone. Use descriptive names based on the token and texture, not the page context (e.g. surface--primary-dark-engraving, not surface--hero).
<section class="surface--cream"> <div class="container">...</div></section>
<section class="surface--stone"> <div class="container">...</div></section>
<section class="my-section surface--navy"> <div class="container">...</div></section>Registering surfaces
Section titled “Registering surfaces”Surfaces live in inc/surfaces/ in the child theme as a PHP file and a paired CSS file:
inc/surfaces/├── surfaces.php # Registers CSS with Wage\Page└── surfaces.css # All surface class definitionssurfaces.php
Section titled “surfaces.php”<?phpWage\Assets::register_global_css( file_get_contents( __DIR__ . '/surfaces.css' ) );surfaces.css
Section titled “surfaces.css”Simple surface (background only)
Section titled “Simple surface (background only)”.surface--cream { background: linear-gradient(180deg, var(--base-ultra-light) 0%, var(--body-background-color) 100%);}Dark surface
Section titled “Dark surface”Dark surfaces include color-scheme: dark alongside their visual treatment. This causes all semantic tokens inside that section to auto-resolve to their dark values:
.surface--velvet { color-scheme: dark; background: radial-gradient(ellipse 70% 60% at 50% 45%, var(--primary) 0%, var(--primary-dark) 50%, var(--primary-ultra-dark) 100%);}For full details on how color schemes work — including the surface--dark utility class, locking components to a scheme, and writing adaptive CSS — see the Color Scheme docs.
Texture surface (with ::after overlay)
Section titled “Texture surface (with ::after overlay)”Texture surfaces are self-contained — they set their own position: relative, isolation: isolate, and ::after pseudo-element:
.surface--stone { position: relative; isolation: isolate;}.surface--stone::after { content: ""; position: absolute; inset: 0; pointer-events: none; z-index: -1; opacity: 0.04; background-image: url("data:image/svg+xml,..."); background-repeat: repeat; background-size: 200px 180px;}Built-in texture patterns
Section titled “Built-in texture patterns”The framework provides three SVG texture patterns commonly used across projects:
| Pattern | Visual | Typical use |
|---|---|---|
| Stone | Brick/ashlar pattern | Heritage, masonry, luxury |
| Engraving | Fine crosshatch lines | Certificates, currency, premium |
| Herringbone | Tweed weave pattern | Textile, craft, warmth |
SVG textures use ::after pseudo-elements at low opacity (0.03-0.06) with a bottom fade mask for a subtle, non-repeating edge.
Image textures (CSS background)
Section titled “Image textures (CSS background)”For tiling image textures used inside a surface’s ::after overlay, the image URL must be injected via a CSS variable because surface CSS is inlined via file_get_contents() — relative URLs won’t resolve.
In surfaces.php, register the CSS variable before the CSS file:
$texture_url = get_stylesheet_directory_uri() . '/assets/images/surface--green-felt-tile.jpg';Wage\Assets::register_global_css( ":root { --surface-velvet-texture: url('{$texture_url}'); }" );Wage\Assets::register_global_css( file_get_contents( __DIR__ . '/surfaces.css' ) );Then reference the variable in surfaces.css:
.surface--velvet::after { content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0; opacity: 0.6; background-image: var(--surface-velvet-texture); background-repeat: repeat; background-size: 212px 212px; mask-image: linear-gradient(to bottom, transparent 0%, black 70%); -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 70%); mix-blend-mode: difference;}Store texture images in assets/images/ in the child theme. For seamless tiling, process the image into a tileable square before use.
Image textures (SectionBackground component)
Section titled “Image textures (SectionBackground component)”For photographic or complex image textures that should be full-bleed (not tiling), use the Wage\SectionBackground component. This renders an <img> element with object-fit: cover:
<section class="my-section"> <?php echo new \Wage\SectionBackground( id: $image_id, opacity: 0.15 ); ?> <div class="container">...</div></section>CSS loading
Section titled “CSS loading”Wage\Assets::register_global_css() collects CSS into a static pool. When Wage\Page::render() is called, it enqueues this pool as an inline <style id="wage-global"> block in <head> — before component CSS but after the core stylesheet.
Because surfaces.php calls register_global_css() at the top level of the file (not inside a class constructor), the CSS registers as soon as the file is require_once’d during bootstrap. This means surface CSS loads on every page, which is fine because it is small (a few gradient declarations and texture blocks).
This is different from component CSS, which only loads when a component is instantiated on a specific page.
Wireframe mode
Section titled “Wireframe mode”Core’s flag CSS automatically hides texture overlays in wireframe mode:
body.wireframe [class*="surface--"]::after { display: none; }This is output by Wage\Flags::output_css() when the wireframe flag is active.
- Surfaces are project-specific. Never add them to the parent theme. Each project defines its own set in
inc/surfaces/. - One surface = one class. Never stack two surface classes on the same element. Each surface class includes its background + texture together.
- Named by token role + texture. Use
surface--primary-dark-engraving,surface--base-light-herringbone— not contextual names likesurface--hero. - Use tokens in surface definitions. Reference
var(--base-ultra-light),var(--body-background-color), etc. — never hardcode brand colours. - Dark surfaces include
color-scheme: dark. See Color Scheme for the full system. - Surfaces can be combined with component classes. For example:
<section class="testimonials surface--primary-dark-engraving">. - SVG textures use
::afterpseudo-elements at low opacity with bottom fade mask. - Image textures use
Wage\SectionBackgroundcomponent for lazy loading.