Foundations
The raw material - type, color, spacing and the small utilities everything else is built from.
Typography
The heading scale, the body text and everything the framework sets on bare
elements. Headings carry text-wrap: balance and a touch of
negative tracking, paragraphs text-wrap: pretty.
h1 and h2 interpolate between 375px and 768px
instead of stepping at a breakpoint - a phone and a desktop keep the sizes
they had, the widths in between grow with the viewport.
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
In the complex world of code, simplicity is the ultimate sophistication.
Extra Small Text
Small Text
Base Text
Medium Text
Large Text
Extra Large Text
This is a standard paragraph with default styling. MaverickWave CSS framework uses clean typography with good readability as a foundation for all text elements.
Secondary text uses a slightly muted color for less emphasis, perfect for supporting content, captions, or metadata.
Bold text and italic text are supported as well, allowing for proper content hierarchy and emphasis.
This is a light text.
Text can be colored using utility classes to highlight important information or match your brand.
Text can be colored using utility classes to highlight important information or match your brand.
Very important error text!
This always remains the text color of the dark theme.
This always remains the text color of the light theme.
Main Colors
These thirteen are the only colors you ever set. Everything else - hover
tones, translucent backgrounds, borders, muted text, the card and footer
surfaces, the ink variant the dark theme needs - is derived from them at
runtime with
color-mix() and relative color syntax, so overriding a root token
cascades to all of its variants.
Primary
#000000
Secondary
#000000
Success
#000000
Warning
#000000
Danger
#000000
Info
#000000
Gray
#000000
Accent Text
#000000
Dark Page
#000000
Dark Text
#000000
Light Page
#000000
Light Text
#000000
Form Elements
#000000
Fill or Ink
Every brand and status colour comes in two tokens.
--mw-primary-color is the exact colour, for anything it
fills - buttons, badges, bars - with
--mw-primary-accent-text-color on top.
--mw-primary-text-color is the same colour as ink
on a theme surface: text, icons, focus rings, accent borders.
A colour picked to carry a label is by definition too dark or too light to be
read on the page it sits on. The ink token clamps OKLch lightness - at least
0.68 on the dark page, at most 0.55 on the light one - and keeps hue and
chroma, so it works for any palette: a dark colour gets lifted, a very light
one deepened, and a colour already in range passes through untouched. Toggle
the theme and watch the second row.
Fill - --mw-*-color
Ink - --mw-*-text-color
Primary text, links and icons
Secondary accent
Success
Warning
Danger
Info
Label Ink Per Colour
--mw-accent-text-color is the label on every solid coloured
surface, and one value for all six only holds while the whole palette sits on
the same side of the lightness scale. A neon green primary next to a deep blue
secondary needs a dark label on the one and a light label on the other, so
every colour carries its own override:
--mw-primary-accent-text-color,
--mw-secondary-accent-text-color and the same for
success, warning, danger and
info. Each one defaults to --mw-accent-text-color,
so nothing changes until you set one.
:root {
--mw-primary-color: #39ff14;
/* the shared label stays light for the rest of the palette ... */
--mw-accent-text-color: #f2f6fc;
/* ... only the neon primary gets a dark one */
--mw-primary-accent-text-color: #0b0f0a;
}
Everything that fills a surface with that colour follows: buttons and mini
buttons, the burger button, table and panel headers, card badges and ribbons,
segmented and tab items, stepper dots, calendar selection, timeline dates,
accordion headers and progress labels. The burger button switches to
--mw-secondary-accent-text-color while the drawer is open,
because its surface does the same - override
--mw-header-burgerbutton-color and
--mw-header-burgerbutton-open-color to break out of that.
Tinted surfaces follow one rule as well:
--mw-*-background is 20% of the colour,
--mw-*-background-hover 45%. Both stay close enough to the
surface underneath that --mw-text-color keeps working on top -
which is what makes an alert, badge or tag readable in either theme.
The surfaces work the same way. Card, footer and border scale the page background's OKLch lightness and chroma by one factor and keep the hue, so a tinted page hands its tint down instead of graying out. A card always steps away from the text colour - darker than the page in the dark theme, lighter in the light one - so content sits on the cleaner surface. That is also why the dark page background is not near-black: the surfaces below it need somewhere to go.
Each factor is an SCSS knob, so how far a card sits from the page is one
number per theme. Below 1 steps toward black, above 1 toward white - read
0.85 as "the card sits at 85% of the page's lightness". Move both
card knobs toward 1 for a flat, borderless look, push them apart for cards
that read as raised panels. Keep the footer further out than the card in the
dark theme and on the other side in the light one, or the band under the page
stops reading as chrome.
@use 'maverick-wave/src/scss/main' with (
$card-surface-dark: 0.85, // card, dark theme
$card-surface-light: 1.05, // card, light theme
$footer-surface-dark: 0.75, // footer and header chrome
$footer-surface-light: 0.95
);
Utilities
The classes that do exactly one thing: spacing, flex, display, text, elevation, aspect ratio. Worth checking before writing a rule of your own - most one-off styles in an application turn out to be a utility that already exists.
Spacing Utilities
Auto Margins
Every margin utility also takes auto -
mw-mx-auto centers a block, mw-ml-auto pushes a
flex item to the far side.
Display & Flex Utilities
Flex Row
Flex Column
Alignment
Align Self
mw-items-* sets the rule for the whole container,
mw-self-* lets a single child break out of it.
Gap Utilities
Different Gap Sizes (from 0 - 14)
Small gap (gap-2)
Medium gap (gap-4)
Large gap (gap-7)
Split Rows
The most common row in any interface: what it is on the left, the value or the
action on the right. mw-row-split wraps, so on a narrow screen
the right half drops below instead of squashing the left one.
mw-row-split-center switches from baseline to center alignment,
for a row that mixes text with a button or an icon.
Team members
Numbers
mw-text-numeric gives fixed-width digits and nothing else - for a
clock, a counter or an ID that must not jitter while it changes.
mw-text-currency adds right alignment and prevents wrapping
mid-number, which is what a money column in a table wants.
mw-text-numeric
00:11:38
mw-text-currency
15,930.25
Screen Reader Only
mw-sr-only hides text visually but keeps it in the accessibility
tree - the label an icon-only button still owes its user.
display: none would not do: it drops the element out of that tree
as well. The two buttons below look identical; only one of them says what it
does.
<span class="mw-sr-only">Delete invoice</span>
Tooltips
Put data-tooltip="..." on any element - pure CSS, no script
needed. The bubble sits above the element on hover or keyboard focus and long
text wraps instead of running off in one endless line. It reaches outside a
card, because cards only clip their content when they carry a ribbon. What
does still cut it off: a scroll container, and the edge of the screen.
Add mw-tooltip-below to put it underneath instead - for a control
in a fixed header, where above is off the screen.
mw-tooltip-end and mw-tooltip-start line the bubble
up with that edge of the trigger rather than centring it, for a trigger close
to the side of the screen. The two axes combine, and the arrow keeps pointing
at the trigger by itself.
Works on inline elements too:
a link,
a code span or
an icon.
Text Overflow & Wrapping
The two ways a long string is cut short, and they are not interchangeable:
mw-text-truncate is one line ending in an ellipsis,
mw-text-clamp-2 through -5 is that many lines ending
in one. Truncation carries min-width: 0 with it, which is the
reason it "does not work" nine times out of ten inside a flex row.
mw-text-truncate
One line only: this sentence is far longer than the box it has been given and ends in an ellipsis rather than wrapping.
mw-text-clamp-2
Two lines and then an ellipsis. This paragraph runs on for long enough that the third line is cut off, which is what a card preview or a list subtitle wants when the copy is not yours to control.
mw-text-break
https://example.com/a/very/long/url/that/has/no/spaces/in/it/at/all/and/would/otherwise/push/the/page/sideways
mw-text-balance and mw-text-pretty
Headings get balance by default - it evens the lines out so
no headline leaves one word alone on the last one. Paragraphs get
pretty, which only prevents the orphan. Both are on already;
the classes are for anything the framework does not style itself.
mw-text-eyebrow
Release notes
The kicker above a heading
mw-text-measure
Caps a column at 68 characters. Past roughly 75 the eye loses the start of the next line on the way back, which is why a full-width paragraph on a desktop is harder to read than a narrow one.
Elevation
The same five-step ramp every component uses, as classes. Each level is two
shadows: a tight contact layer that gives the box weight, and a wide ambient
one that says how high it floats. One layer alone reads as a blur behind the
box - the pair reads as light. mw-elevation-0 is explicitly flat,
for taking something off the page it normally floats above.
1 · resting
Inputs, tags, small controls.
2 · raised
Cards and panels at rest.
3 · floating
A card under the pointer.
4 · overlay
Dropdowns, popovers, drawer.
5 · modal
The dialog over everything.
0 · flat
Explicitly on the page.
Glow
The other half of the lighting model: elevation says how far a surface floats
above the page, a glow says it is the thing giving off the light. Two layers
like elevation, and both without an offset - light does not fall downwards,
which is the whole difference between this and a coloured shadow. For the one
element on a screen that has to be looked at first, and for nothing else. Bare
mw-glow is the primary one.
primary
The brand, and the default.
secondary
The second brand tone.
info
Something worth reading.
success
It worked - say so once.
warning
Check this before going on.
danger
The one that cannot be undone.
Responsive Display
Mobile-first and min-width, like everything else here.
mw-d-md-flex means "flex from the md breakpoint up", and the
unprefixed class beside it is what applies below that - the pair
mw-d-none mw-d-md-flex is hidden on a phone and a row from a
tablet on. Variants exist for sm, md,
lg and xl.
mw-hide-mobile
mw-hide-desktop
Resize the window past 768px to see the two swap.
Aspect Ratio
Reserves the box before the image inside it has loaded, which is the whole
point: without it the page reflows when the picture arrives and everything
below jumps. The child fills the box and crops rather than stretching.
mw-aspect-square, -video, -wide,
-portrait, -photo.
square
video
photo
Squircle Corners
mw-squircle draws the framework silhouette with a superellipse
instead of a circular arc - same four radii, fuller curve. Opt-in, because
corner-shape only lands in Chromium so far; everywhere else the
card below is simply the normal one.
Circular corner radii.
Superellipse, corner accent follows.
Image Shapes
A cut-out photo instead of another rectangle.
mw-shape-arch rounds the top into a half circle,
mw-shape-signature gives a picture the same sharp and round
diagonal as the cards next to it, and mw-shape-leaf opens the
round pair up to the full side. All three follow
--mw-radius-scale where they have a radius to follow, and work on
an img or on a wrapper around one.
Site-wide Variants
Fifteen classes on <html> retune the whole look without
touching markup. They stack, and the palette button in the corner switches all
of them live - the box at the bottom of that panel prints the setup a project
would carry, and reads it back: paste one in to see someone else's.
-
mw-corners-even- drops the surface signature; every panel becomes an evenly rounded box -
mw-accent-single- one brand colour instead of two,mw-btn-secondaryturns outline -
mw-accent-text-auto- the label on every filled colour turns black or white bycontrast-color(), where the browser has it -
mw-shadows-flat- elevation 1-3 tonone, dropdown and modal keep theirs -
mw-shadows-hard- every elevation turns into a hard offset without blur;--mw-shadow-hardsets its colour -
mw-surfaces-flush- cards, panels and footer on the page colour, held by their border -
mw-hover-static- no hover travels; colour and border still respond -
mw-motion-off- the reduced-motion page for everyone, script included; the static pair around it are two of its parts -
mw-scroll-static- no scroll entrance;mw-revealblocks sit where they land -
mw-sections-plain- the hatch behindmw-section-alternatecollapses into the page colour mw-headings-caps- h1 to h3 in capitals-
mw-btn-pill- fully rounded buttons, form fields keep their radius -
mw-btn-square- the other end of that axis: buttons cut to a hard corner while the page keeps its radius -
mw-btn-tactile- filled buttons stand on a darker edge and sink onto it when pressed -
mw-btn-glass- filled buttons become tinted glass with a lit top edge
Five properties do the rest: --mw-radius-scale multiplies every
radius and --mw-root-font-size the whole rem scale, plus
--mw-font-family-heading, --mw-container-width and
--mw-section-padding-block.
Header Utilities
The controls that live in the bar itself rather than on the page: the theme switch, the language switcher and the login button. All of them are real buttons, so they are reachable by keyboard - the theme switch in particular is the first thing someone with a light-sensitivity need goes looking for.
Color Switcher (on a fake header here)
This one is not clickable - the real switcher sits in the header at the top of the page.
Language Switcher (on a fake header here)
A .mw-dropdown with a quieter trigger: no fill and no border
until you touch it, so the bar keeps two calm controls instead of a row of
buttons. The two-letter code is what states the current language - a flag is
a country, and no country stands for English. The flag is only what the eye
finds first. Picking one fires mw-language-change on the
switcher; loading the translations is the application's job.
The flags are drawn in CSS gradients, so they cost no request and no icon
font. Emoji were not an option: Windows ships no flag glyphs, and Chrome and
Edge render the German one as the two letters "DE" in a box. Anything not in
the set below takes an <img> or an inline
<svg> inside .mw-flag, which hands it the
same box, corner and hairline.
Localhost Indicator (on a fake header here)
This is what the localhost indicator looks like when it has been activated (so that you can recognise in the header that you are currently working locally)
Profile Button (on a fake header here)
Shows who is signed in: an avatar with initials plus the name. Below
md the name steps aside and only the round avatar remains, so
it keeps the same height as the login and burger buttons. Works outside a
header too - in a panel header or a toolbar. mw-header-btn is
the round icon control beside it - search, notifications - with the same
border, hover and focus.
Without initials it also takes an icon:
Coming Soon Banner
A placeholder for a section that is not built yet. Loud on purpose: the whole point is that nobody ships it by accident.
Divider
A rule between two things - horizontal or vertical, solid or dashed, in a brand colour, or with a label sitting in the middle of it.
Horizontal
Default
Content above
Content below