Depth & Shadows
How Frequency uses surface elevation, shadows, and borders to create hierarchy without visual noise.
Our Approach
Frequency uses subtle shadows as its primary depth strategy. Shadows are whisper-quiet — just enough to separate surfaces without drawing attention. We never use heavy drop shadows or dramatic elevation changes.
The system is simple: surfaces float slightly above the canvas with a consistent 0 1px 2px rgba(0, 0, 0, 0.05) shadow. Navigation gets a slightly stronger 0 1px 3px rgba(0, 0, 0, 0.12) to anchor it at the top of the page. That’s it.
Shadow Scale
| Token | Value | Usage |
|---|---|---|
| None | none | Flat elements, inline content |
| Default | 0 1px 2px rgba(0, 0, 0, 0.05) | Cards, Paper, tables, code blocks |
| Navigation | 0 1px 3px rgba(0, 0, 0, 0.12) | Navbar, sticky headers |
| Hover | var(--mantine-shadow-sm) | Interactive cards on hover |
We only use two shadow values in practice. If you need more than two, reconsider the design.
What We Don’t Do
Don't
Mix shadow intensities arbitrarily or use shadows heavier than sm
Do
Use the same subtle shadow consistently across all surfaces
Surface Hierarchy
Instead of relying on shadows alone, Frequency creates depth through background color stepping. Each level is a small increment in lightness.
Light Mode Surfaces
| Token | Value | Usage |
|---|---|---|
--mantine-color-body | #f7f7f7 | Page canvas, base layer |
--brand-card-bg | #ffffff | Cards, panels, content areas |
--brand-card-bg-deep | #f0f0f0 | Recessed areas within cards |
--brand-card-bg-deepest | #e8e8e8 | Deeply nested containers |
Dark Mode Surfaces
| Token | Value | Usage |
|---|---|---|
--mantine-color-body | #1a1a1a | Page canvas, base layer |
--brand-card-bg | #242424 | Cards, panels, content areas |
--brand-card-bg-deep | #2e2e2e | Recessed areas within cards |
--brand-card-bg-deepest | #383838 | Deeply nested containers |
The pattern: in light mode, cards are lighter than the canvas. In dark mode, elevated surfaces are lighter than the base. The difference between levels is always subtle — a few percentage points of lightness.
Border Tokens
Borders are used sparingly and at low opacity. They define regions without demanding attention.
Light Mode
| Token | Value | Usage |
|---|---|---|
--brand-border-subtle | rgba(0, 0, 0, 0.08) | Quiet separation lines |
--brand-border-medium | rgba(0, 0, 0, 0.12) | Standard dividers |
--brand-outline | rgba(0, 0, 0, 0.15) | Input outlines, stronger definition |
Dark Mode
| Token | Value | Usage |
|---|---|---|
--brand-border-subtle | rgba(255, 255, 255, 0.05) | Quiet separation lines |
--brand-border-medium | rgba(255, 255, 255, 0.1) | Standard dividers |
--brand-outline | rgba(255, 255, 255, 0.3) | Input outlines, stronger definition |
Border Guidelines
Don't
Add visible borders between every element for structure
Do
Use background color differences to separate sections instead of borders
- If borders are the first thing you notice, they’re too strong
- If you can’t tell where regions begin and end, they’re too subtle
- Default to
--brand-border-subtle— reach formediumoroutlineonly when needed
Implementation
Cards and Panels
Every Paper and Card component gets the default subtle shadow automatically via globals.css. No need to add shadow props manually.
/* Applied globally to all Paper and Card components */
.mantine-Paper-root {
background-color: var(--paper-bg, var(--mantine-color-body));
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}Interactive Cards
Cards that respond to hover should lift slightly using Mantine’s shadow-sm:
.interactive-card:hover {
transform: translateY(-2px);
box-shadow: var(--mantine-shadow-sm);
}Tables
Tables use the same subtle shadow, with rounded corners and hidden overflow:
.mantine-Table-table {
border-radius: var(--mantine-radius-md);
overflow: hidden;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}Code Blocks
Code blocks follow the same pattern — no borders, just the standard subtle shadow:
pre, [data-rehype-pretty-code-figure] {
border: none;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}Dark Mode Considerations
In dark mode, shadows become nearly invisible against dark backgrounds. The system compensates by:
- Relying more on surface color stepping — the
#1a1a1a→#242424→#2e2e2eprogression does most of the work - Using borders more for definition — dark mode borders use white at low opacity (
rgba(255, 255, 255, 0.05–0.1)) - Keeping shadows anyway — even though less visible, the subtle shadow still adds a hint of depth on lighter-on-dark surfaces
| Concern | Light Mode | Dark Mode |
|---|---|---|
| Primary depth cue | Shadow + color stepping | Color stepping + borders |
| Border opacity | 0.08–0.15 | 0.05–0.3 |
| Shadow visibility | Clearly visible | Barely visible, supplementary |
Quick Reference
Use shadow: Cards, Paper, tables, code blocks, navigation Use color stepping: Section backgrounds, nested containers, recessed areas Use borders: Only when shadow + color stepping isn’t enough (inputs, explicit dividers)
Never:
- Use
box-shadowvalues heavier thanvar(--mantine-shadow-sm) - Mix bordered cards with shadowed cards in the same view
- Add borders for visual separation when background color differences work
- Use
!importanton shadows (the global styles handle it)