Skip to Content
GuidelinesDepth & Shadows

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

TokenValueUsage
NonenoneFlat elements, inline content
Default0 1px 2px rgba(0, 0, 0, 0.05)Cards, Paper, tables, code blocks
Navigation0 1px 3px rgba(0, 0, 0, 0.12)Navbar, sticky headers
Hovervar(--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

TokenValueUsage
--mantine-color-body#f7f7f7Page canvas, base layer
--brand-card-bg#ffffffCards, panels, content areas
--brand-card-bg-deep#f0f0f0Recessed areas within cards
--brand-card-bg-deepest#e8e8e8Deeply nested containers

Dark Mode Surfaces

TokenValueUsage
--mantine-color-body#1a1a1aPage canvas, base layer
--brand-card-bg#242424Cards, panels, content areas
--brand-card-bg-deep#2e2e2eRecessed areas within cards
--brand-card-bg-deepest#383838Deeply 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

TokenValueUsage
--brand-border-subtlergba(0, 0, 0, 0.08)Quiet separation lines
--brand-border-mediumrgba(0, 0, 0, 0.12)Standard dividers
--brand-outlinergba(0, 0, 0, 0.15)Input outlines, stronger definition

Dark Mode

TokenValueUsage
--brand-border-subtlergba(255, 255, 255, 0.05)Quiet separation lines
--brand-border-mediumrgba(255, 255, 255, 0.1)Standard dividers
--brand-outlinergba(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 for medium or outline only 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:

  1. Relying more on surface color stepping — the #1a1a1a#242424#2e2e2e progression does most of the work
  2. Using borders more for definition — dark mode borders use white at low opacity (rgba(255, 255, 255, 0.05–0.1))
  3. Keeping shadows anyway — even though less visible, the subtle shadow still adds a hint of depth on lighter-on-dark surfaces
ConcernLight ModeDark Mode
Primary depth cueShadow + color steppingColor stepping + borders
Border opacity0.08–0.150.05–0.3
Shadow visibilityClearly visibleBarely 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-shadow values heavier than var(--mantine-shadow-sm)
  • Mix bordered cards with shadowed cards in the same view
  • Add borders for visual separation when background color differences work
  • Use !important on shadows (the global styles handle it)
Last updated on