Data Viz Art is a web design aesthetic that elevates data visualization from a functional communication tool into a primary design element – treating charts, graphs, infographics, and analytical displays as the visual centerpiece of a page rather than supplementary illustrations. Rooted in the work of pioneers like Edward Tufte, Giorgia Lupi, Stefanie Posavec, and the Information is Beautiful movement led by David McCandless, this aesthetic blurs the line between analytical rigor and artistic expression. Where traditional web design uses photography or illustration as hero content, Data Viz Art places beautifully rendered scatter plots, radial charts, flow diagrams, and annotated data canvases at the center of the visual experience.
The philosophy draws heavily from Giorgia Lupi’s concept of “Data Humanism” – the idea that data is always a placeholder for real human stories, and that visualization should reconnect numbers to the lives and contexts they represent. This gives the aesthetic its distinctive warmth: despite being built on precision and measurement, Data Viz Art websites feel personal, narrative-driven, and deeply intentional. Every axis label, every color gradient, every annotation is a deliberate design choice that serves both comprehension and beauty.
Visually, the style is characterized by clean, expansive layouts that give breathing room to complex visualizations. Color palettes are carefully curated – often drawing from sequential, diverging, or categorical color systems used in scientific publishing, but refined for screen aesthetics. Typography tends toward high-readability sans-serif families with strong tabular number support, paired with monospace or technical display faces for data labels. Grids are generous, whitespace is abundant, and the overall impression is one of calm authority: the design whispers confidence rather than shouting for attention.
This aesthetic has gained significant traction in editorial data journalism (The New York Times, The Pudding, Reuters Graphics), analytical SaaS dashboards, scientific communication platforms, and portfolio sites for data artists. It appeals to audiences who value intellectual depth and visual sophistication – people who find a well-crafted slope chart as compelling as a full-bleed photograph.
The palette is structured around the three systems used in professional data visualization: a categorical palette for nominal groupings, a sequential gradient for ordered data, and a set of neutral interface tones. Colors are chosen for perceptual uniformity, colorblind safety, and screen readability – beauty emerges from their systematic application rather than individual vibrancy.
| Color Name | Hex | Role / Usage |
|---|---|---|
| Deep Ink | #1B2A4A |
Primary text, headings, axis labels |
| Slate | #4A5568 |
Secondary text, descriptions, annotation body |
| Graphite | #718096 |
Tertiary text, captions, tick labels |
| Mist | #E2E8F0 |
Gridlines, dividers, subtle borders |
| Canvas | #F7FAFC |
Page background, chart area fill |
| White | #FFFFFF |
Card backgrounds, tooltip surfaces |
| Signal Blue | #3182CE |
Primary data series, links, interactive elements |
| Coral | #E53E3E |
Negative values, alerts, decline indicators |
| Teal | #319795 |
Secondary data series, complementary category |
| Amber | #D69E2E |
Tertiary data series, warning, highlight annotations |
| Violet | #805AD5 |
Fourth data series, qualitative category |
| Seafoam | #38B2AC |
Fifth data series, positive trend accent |
| Rose | #ED64A6 |
Sixth data series, qualitative category |
| Midnight | #0F1B2D |
Dark mode background, high-contrast panels |
| Glow | #63B3ED |
Hover highlights, active data point emphasis |
:root {
/* Interface Tones */
--dvz-bg: #f7fafc;
--dvz-surface: #ffffff;
--dvz-border: #e2e8f0;
--dvz-gridline: #e2e8f0;
/* Text Hierarchy */
--dvz-text-primary: #1b2a4a;
--dvz-text-secondary: #4a5568;
--dvz-text-tertiary: #718096;
/* Categorical Data Palette */
--dvz-cat-1: #3182ce;
--dvz-cat-2: #e53e3e;
--dvz-cat-3: #319795;
--dvz-cat-4: #d69e2e;
--dvz-cat-5: #805ad5;
--dvz-cat-6: #38b2ac;
--dvz-cat-7: #ed64a6;
/* Semantic Colors */
--dvz-positive: #38a169;
--dvz-negative: #e53e3e;
--dvz-neutral: #718096;
--dvz-highlight: #63b3ed;
/* Dark Surfaces */
--dvz-dark-bg: #0f1b2d;
--dvz-dark-surface: #1b2a4a;
/* Layout Tokens */
--dvz-chart-padding: 32px;
--dvz-card-radius: 8px;
--dvz-gap: 24px;
--dvz-max-width: 1200px;
}
Data Viz Art typography prioritizes legibility at small sizes, precise number rendering, and a sense of scientific credibility. Fonts must perform well as chart labels at 10px, as annotation text at 13px, and as editorial headings at 48px. Sans-serif families dominate because they scale better on screens and avoid the visual noise that serifs introduce at small sizes. Monospace faces appear in data labels, code annotations, and tabular displays where digit alignment matters.
| Font | Style | Best For |
|---|---|---|
| Inter | Humanist sans-serif, tall x-height | Body text, descriptions, general UI – exceptional at small sizes |
| IBM Plex Sans | Neo-grotesque, technical feel | Headlines, axis labels, data annotations – strong tabular figures |
| IBM Plex Mono | Monospace companion | Data values, code snippets, chart tick labels, table numbers |
| Source Sans 3 | Adobe’s open-source workhorse | Long-form body text, annotations, captions |
| Roboto | Google’s default, neutral clarity | Dashboard interfaces, chart labels, compact layouts |
| Space Grotesk | Monospace-inspired proportional | Display headings, metric callouts, modern data aesthetic |
| JetBrains Mono | Developer-focused monospace | Raw data display, code blocks, terminal-style data feeds |
| DM Sans | Clean geometric | Section headings, navigation, complementary display face |
| Heading Font | Body Font | Data Font | Character |
|---|---|---|---|
| Space Grotesk (700) | Inter (400) | IBM Plex Mono (400) | Modern editorial data journalism |
| IBM Plex Sans (600) | IBM Plex Sans (400) | IBM Plex Mono (400) | Unified technical, IBM-style dashboards |
| DM Sans (700) | Source Sans 3 (400) | JetBrains Mono (400) | Clean, developer-oriented analytics |
| Inter (700) | Inter (400) | IBM Plex Mono (400) | Minimalist, all-purpose data platform |
| Space Grotesk (600) | Source Sans 3 (400) | IBM Plex Mono (400) | Scientific publication, research reports |
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap');
h1, h2, h3, h4, h5, h6 {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
color: var(--dvz-text-primary);
line-height: 1.2;
letter-spacing: -0.02em;
}
body {
font-family: 'Inter', sans-serif;
font-weight: 400;
font-size: 1rem;
line-height: 1.7;
color: var(--dvz-text-secondary);
}
.dvz-display {
font-family: 'Space Grotesk', sans-serif;
font-size: clamp(2.5rem, 5vw, 4rem);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.1;
}
.dvz-data-label {
font-family: 'IBM Plex Mono', monospace;
font-weight: 500;
font-size: 0.75rem;
letter-spacing: 0.02em;
color: var(--dvz-text-tertiary);
}
.dvz-metric {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
font-size: 3rem;
letter-spacing: -0.03em;
line-height: 1;
font-variant-numeric: tabular-nums;
}
.dvz-annotation {
font-family: 'Inter', sans-serif;
font-weight: 400;
font-size: 0.85rem;
font-style: italic;
color: var(--dvz-text-tertiary);
line-height: 1.5;
}
.dvz-axis-label {
font-family: 'IBM Plex Mono', monospace;
font-weight: 400;
font-size: 0.7rem;
fill: var(--dvz-text-tertiary);
text-transform: uppercase;
letter-spacing: 0.08em;
}
.dvz-caption {
font-family: 'Inter', sans-serif;
font-weight: 400;
font-size: 0.85rem;
color: var(--dvz-text-tertiary);
border-left: 3px solid var(--dvz-cat-1);
padding-left: 12px;
}
viewBox attributes; canvas-based charts redraw at breakpoints.dvz-card {
background: var(--dvz-surface);
border: 1px solid var(--dvz-border);
border-radius: var(--dvz-card-radius);
padding: var(--dvz-chart-padding);
transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.dvz-card:hover {
box-shadow: 0 4px 20px rgba(27, 42, 74, 0.08);
transform: translateY(-1px);
}
.dvz-card__header {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 20px;
padding-bottom: 12px;
border-bottom: 1px solid var(--dvz-border);
}
.dvz-card__title {
font-family: 'Space Grotesk', sans-serif;
font-weight: 600;
font-size: 1rem;
color: var(--dvz-text-primary);
}
.dvz-card__subtitle {
font-family: 'IBM Plex Mono', monospace;
font-size: 0.75rem;
color: var(--dvz-text-tertiary);
letter-spacing: 0.02em;
}
.dvz-card__chart-area {
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
}
.dvz-card__footer {
display: flex;
align-items: center;
gap: 16px;
margin-top: 16px;
padding-top: 12px;
border-top: 1px solid var(--dvz-border);
font-family: 'IBM Plex Mono', monospace;
font-size: 0.7rem;
color: var(--dvz-text-tertiary);
}
.dvz-button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
background: var(--dvz-cat-1);
color: #ffffff;
border: none;
border-radius: 6px;
padding: 10px 24px;
font-family: 'Inter', sans-serif;
font-weight: 600;
font-size: 0.875rem;
cursor: pointer;
transition: background 0.2s ease, transform 0.15s ease;
text-decoration: none;
}
.dvz-button:hover {
background: #2c5282;
transform: translateY(-1px);
}
.dvz-button--outline {
background: transparent;
color: var(--dvz-cat-1);
border: 1.5px solid var(--dvz-cat-1);
}
.dvz-button--outline:hover {
background: rgba(49, 130, 206, 0.08);
transform: translateY(-1px);
}
.dvz-button--ghost {
background: transparent;
color: var(--dvz-text-secondary);
padding: 8px 16px;
}
.dvz-button--ghost:hover {
background: var(--dvz-border);
color: var(--dvz-text-primary);
}
.dvz-button--small {
padding: 6px 14px;
font-size: 0.75rem;
border-radius: 4px;
}
.dvz-button--icon {
width: 36px;
height: 36px;
padding: 0;
border-radius: 6px;
}
.dvz-nav {
display: flex;
align-items: center;
justify-content: space-between;
max-width: var(--dvz-max-width);
margin: 0 auto;
padding: 16px 24px;
border-bottom: 1px solid var(--dvz-border);
}
.dvz-nav__logo {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
font-size: 1.2rem;
color: var(--dvz-text-primary);
text-decoration: none;
display: flex;
align-items: center;
gap: 8px;
}
.dvz-nav__logo-mark {
width: 28px;
height: 28px;
background: var(--dvz-cat-1);
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
}
.dvz-nav__links {
display: flex;
gap: 32px;
list-style: none;
margin: 0;
padding: 0;
}
.dvz-nav__links a {
font-family: 'Inter', sans-serif;
font-weight: 500;
font-size: 0.875rem;
color: var(--dvz-text-tertiary);
text-decoration: none;
transition: color 0.2s ease;
position: relative;
}
.dvz-nav__links a:hover {
color: var(--dvz-text-primary);
}
.dvz-nav__links a.active {
color: var(--dvz-cat-1);
}
.dvz-nav__links a.active::after {
content: '';
position: absolute;
bottom: -18px;
left: 0;
right: 0;
height: 2px;
background: var(--dvz-cat-1);
}
.dvz-nav__actions {
display: flex;
align-items: center;
gap: 12px;
}
.dvz-hero {
max-width: var(--dvz-max-width);
margin: 0 auto;
padding: 80px 24px 60px;
display: grid;
grid-template-columns: 1fr 1.2fr;
gap: 60px;
align-items: center;
}
.dvz-hero__content {
max-width: 480px;
}
.dvz-hero__eyebrow {
font-family: 'IBM Plex Mono', monospace;
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--dvz-cat-1);
margin-bottom: 16px;
}
.dvz-hero__title {
font-family: 'Space Grotesk', sans-serif;
font-size: clamp(2.5rem, 5vw, 3.5rem);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.1;
color: var(--dvz-text-primary);
margin-bottom: 20px;
}
.dvz-hero__description {
font-family: 'Inter', sans-serif;
font-size: 1.1rem;
line-height: 1.7;
color: var(--dvz-text-tertiary);
margin-bottom: 32px;
}
.dvz-hero__chart {
background: var(--dvz-surface);
border: 1px solid var(--dvz-border);
border-radius: var(--dvz-card-radius);
padding: 24px;
min-height: 360px;
display: flex;
flex-direction: column;
}
@media (max-width: 768px) {
.dvz-hero {
grid-template-columns: 1fr;
padding: 40px 16px 32px;
gap: 32px;
}
}
.dvz-chart-grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: var(--dvz-gap);
max-width: var(--dvz-max-width);
margin: 0 auto;
padding: 0 24px;
}
.dvz-chart-grid--col-4 { grid-column: span 4; }
.dvz-chart-grid--col-6 { grid-column: span 6; }
.dvz-chart-grid--col-8 { grid-column: span 8; }
.dvz-chart-grid--col-12 { grid-column: span 12; }
.dvz-chart-container {
position: relative;
width: 100%;
overflow: hidden;
}
.dvz-chart-container svg {
width: 100%;
height: auto;
display: block;
}
.dvz-chart-container .gridline {
stroke: var(--dvz-gridline);
stroke-width: 0.5;
opacity: 0.5;
}
.dvz-chart-container .axis-line {
stroke: var(--dvz-text-tertiary);
stroke-width: 1;
}
.dvz-chart-container .data-line {
fill: none;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
@media (max-width: 768px) {
.dvz-chart-grid { grid-template-columns: 1fr; }
.dvz-chart-grid--col-4,
.dvz-chart-grid--col-6,
.dvz-chart-grid--col-8 { grid-column: span 1; }
}
.dvz-tooltip {
position: absolute;
pointer-events: none;
background: var(--dvz-dark-bg);
color: #ffffff;
border-radius: 6px;
padding: 10px 14px;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.75rem;
line-height: 1.5;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
z-index: 100;
opacity: 0;
transform: translateY(4px);
transition: opacity 0.15s ease, transform 0.15s ease;
}
.dvz-tooltip.visible {
opacity: 1;
transform: translateY(0);
}
.dvz-tooltip__label {
font-weight: 500;
color: rgba(255, 255, 255, 0.7);
margin-bottom: 2px;
}
.dvz-tooltip__value {
font-weight: 600;
font-size: 0.85rem;
color: #ffffff;
}
.dvz-tooltip__swatch {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 6px;
vertical-align: middle;
}
.dvz-kpi {
display: flex;
flex-direction: column;
gap: 4px;
}
.dvz-kpi__value {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
font-size: 2.5rem;
letter-spacing: -0.03em;
line-height: 1;
color: var(--dvz-text-primary);
font-variant-numeric: tabular-nums;
}
.dvz-kpi__label {
font-family: 'IBM Plex Mono', monospace;
font-weight: 400;
font-size: 0.7rem;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--dvz-text-tertiary);
}
.dvz-kpi__trend {
display: inline-flex;
align-items: center;
gap: 4px;
font-family: 'IBM Plex Mono', monospace;
font-weight: 500;
font-size: 0.75rem;
}
.dvz-kpi__trend--up {
color: var(--dvz-positive);
}
.dvz-kpi__trend--down {
color: var(--dvz-negative);
}
.dvz-kpi__sparkline {
width: 100%;
height: 40px;
margin-top: 12px;
}
.dvz-kpi__sparkline path {
fill: none;
stroke-width: 1.5;
stroke-linecap: round;
}
| Aesthetic | Relationship to Data Viz Art |
|---|---|
| Flat Design | Shares the emphasis on clean shapes and minimal ornamentation; Data Viz Art adds analytical structure and data-driven color logic |
| Swiss / International Typographic Style | The grid discipline, sans-serif typography, and objective visual language are direct ancestors of Data Viz Art |
| Bento Grid | Modular card layouts that work well for dashboard-style Data Viz Art arrangements with one chart per tile |
| Cyberminimalism | Both reduce visual noise to essential elements; Data Viz Art replaces cyber’s coolness with analytical warmth |
| Neubrutalism | Shares bold type and raw honesty, but Data Viz Art channels that honesty through precise data rather than rough aesthetics |
| Infographic / Editorial | The closest sibling – editorial infographics are essentially Data Viz Art applied to journalistic storytelling |
| Scientific / Academic | Shares rigor and citation culture; Data Viz Art elevates academic chart conventions with refined design polish |
| Corporate Memphis | Often appears alongside data viz in SaaS dashboards; the flat illustration style contrasts with Data Viz Art’s precision |
| Dark Mode / Developer UI | Terminal-inspired interfaces with monospace type and dark backgrounds are a popular Data Viz Art variant for technical audiences |
| Generative Art | Data-driven generative visuals (like those by Jer Thorp or Nicholas Felton) sit at the artistic extreme of the Data Viz Art spectrum |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DataLens -- Data Viz Art</title>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
/* ========================================
CSS Custom Properties
======================================== */
:root {
--dvz-bg: #f7fafc;
--dvz-surface: #ffffff;
--dvz-border: #e2e8f0;
--dvz-gridline: #e2e8f0;
--dvz-text-primary: #1b2a4a;
--dvz-text-secondary: #4a5568;
--dvz-text-tertiary: #718096;
--dvz-cat-1: #3182ce;
--dvz-cat-2: #e53e3e;
--dvz-cat-3: #319795;
--dvz-cat-4: #d69e2e;
--dvz-cat-5: #805ad5;
--dvz-cat-6: #38b2ac;
--dvz-cat-7: #ed64a6;
--dvz-positive: #38a169;
--dvz-negative: #e53e3e;
--dvz-highlight: #63b3ed;
--dvz-dark-bg: #0f1b2d;
--dvz-dark-surface: #1b2a4a;
--dvz-chart-padding: 32px;
--dvz-card-radius: 8px;
--dvz-gap: 24px;
--dvz-max-width: 1200px;
}
/* ========================================
Reset & Base
======================================== */
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: var(--dvz-bg);
color: var(--dvz-text-secondary);
font-family: 'Inter', sans-serif;
font-weight: 400;
font-size: 1rem;
line-height: 1.7;
-webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
color: var(--dvz-text-primary);
line-height: 1.2;
letter-spacing: -0.02em;
}
a { color: var(--dvz-cat-1); text-decoration: none; }
a:hover { text-decoration: underline; }
/* ========================================
Navigation
======================================== */
nav {
display: flex;
align-items: center;
justify-content: space-between;
max-width: var(--dvz-max-width);
margin: 0 auto;
padding: 16px 24px;
border-bottom: 1px solid var(--dvz-border);
}
.logo {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
font-size: 1.2rem;
color: var(--dvz-text-primary);
text-decoration: none;
display: flex;
align-items: center;
gap: 8px;
}
.logo-mark {
width: 28px;
height: 28px;
background: var(--dvz-cat-1);
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
}
.logo-mark svg { width: 16px; height: 16px; }
nav ul {
display: flex;
gap: 32px;
list-style: none;
}
nav ul a {
color: var(--dvz-text-tertiary);
font-weight: 500;
font-size: 0.875rem;
transition: color 0.2s;
}
nav ul a:hover { color: var(--dvz-text-primary); text-decoration: none; }
.nav-actions {
display: flex;
align-items: center;
gap: 12px;
}
/* ========================================
Buttons
======================================== */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
background: var(--dvz-cat-1);
color: #fff;
border: none;
border-radius: 6px;
padding: 10px 24px;
font-family: 'Inter', sans-serif;
font-weight: 600;
font-size: 0.875rem;
cursor: pointer;
transition: background 0.2s, transform 0.15s;
text-decoration: none;
}
.btn:hover {
background: #2c5282;
transform: translateY(-1px);
text-decoration: none;
}
.btn--outline {
background: transparent;
color: var(--dvz-cat-1);
border: 1.5px solid var(--dvz-cat-1);
}
.btn--outline:hover {
background: rgba(49, 130, 206, 0.08);
}
.btn--ghost {
background: transparent;
color: var(--dvz-text-secondary);
padding: 8px 16px;
}
.btn--ghost:hover {
background: var(--dvz-border);
color: var(--dvz-text-primary);
}
/* ========================================
Hero Section
======================================== */
.hero {
max-width: var(--dvz-max-width);
margin: 0 auto;
padding: 80px 24px 60px;
display: grid;
grid-template-columns: 1fr 1.3fr;
gap: 60px;
align-items: center;
}
.hero-eyebrow {
font-family: 'IBM Plex Mono', monospace;
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--dvz-cat-1);
margin-bottom: 16px;
}
.hero h1 {
font-size: clamp(2.5rem, 5vw, 3.5rem);
letter-spacing: -0.03em;
line-height: 1.1;
margin-bottom: 20px;
}
.hero-desc {
font-size: 1.1rem;
line-height: 1.7;
color: var(--dvz-text-tertiary);
margin-bottom: 32px;
max-width: 460px;
}
.hero-actions {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.hero-chart {
background: var(--dvz-surface);
border: 1px solid var(--dvz-border);
border-radius: var(--dvz-card-radius);
padding: 24px;
position: relative;
}
.hero-chart__header {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 16px;
}
.hero-chart__title {
font-family: 'Space Grotesk', sans-serif;
font-weight: 600;
font-size: 0.9rem;
color: var(--dvz-text-primary);
}
.hero-chart__period {
font-family: 'IBM Plex Mono', monospace;
font-size: 0.7rem;
color: var(--dvz-text-tertiary);
}
/* ========================================
KPI Row
======================================== */
.kpi-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--dvz-gap);
max-width: var(--dvz-max-width);
margin: 0 auto;
padding: 0 24px 60px;
}
.kpi-card {
background: var(--dvz-surface);
border: 1px solid var(--dvz-border);
border-radius: var(--dvz-card-radius);
padding: 24px;
}
.kpi-label {
font-family: 'IBM Plex Mono', monospace;
font-weight: 400;
font-size: 0.7rem;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--dvz-text-tertiary);
margin-bottom: 8px;
}
.kpi-value {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700;
font-size: 2rem;
letter-spacing: -0.03em;
line-height: 1;
color: var(--dvz-text-primary);
font-variant-numeric: tabular-nums;
margin-bottom: 8px;
}
.kpi-trend {
font-family: 'IBM Plex Mono', monospace;
font-weight: 500;
font-size: 0.75rem;
display: inline-flex;
align-items: center;
gap: 4px;
}
.kpi-trend--up { color: var(--dvz-positive); }
.kpi-trend--down { color: var(--dvz-negative); }
/* ========================================
Chart Dashboard Grid
======================================== */
.dashboard {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: var(--dvz-gap);
max-width: var(--dvz-max-width);
margin: 0 auto;
padding: 0 24px 60px;
}
.chart-card {
background: var(--dvz-surface);
border: 1px solid var(--dvz-border);
border-radius: var(--dvz-card-radius);
padding: var(--dvz-chart-padding);
display: flex;
flex-direction: column;
}
.chart-card--col-8 { grid-column: span 8; }
.chart-card--col-6 { grid-column: span 6; }
.chart-card--col-4 { grid-column: span 4; }
.chart-card--col-12 { grid-column: span 12; }
.chart-card__header {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 20px;
padding-bottom: 12px;
border-bottom: 1px solid var(--dvz-border);
}
.chart-card__title {
font-family: 'Space Grotesk', sans-serif;
font-weight: 600;
font-size: 1rem;
}
.chart-card__meta {
font-family: 'IBM Plex Mono', monospace;
font-size: 0.7rem;
color: var(--dvz-text-tertiary);
}
.chart-card__body {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
min-height: 200px;
}
.chart-card__footer {
display: flex;
align-items: center;
gap: 16px;
margin-top: 16px;
padding-top: 12px;
border-top: 1px solid var(--dvz-border);
font-family: 'IBM Plex Mono', monospace;
font-size: 0.7rem;
color: var(--dvz-text-tertiary);
}
.chart-card__legend {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.legend-item {
display: flex;
align-items: center;
gap: 6px;
font-family: 'Inter', sans-serif;
font-size: 0.75rem;
color: var(--dvz-text-tertiary);
}
.legend-swatch {
width: 10px;
height: 10px;
border-radius: 2px;
}
/* ========================================
Annotation / Insight Section
======================================== */
.insight-section {
max-width: var(--dvz-max-width);
margin: 0 auto;
padding: 60px 24px;
display: grid;
grid-template-columns: 1fr 1.5fr;
gap: 60px;
align-items: start;
}
.insight-section h2 {
font-size: 1.8rem;
margin-bottom: 16px;
}
.insight-text {
font-size: 1rem;
line-height: 1.8;
color: var(--dvz-text-secondary);
margin-bottom: 16px;
}
.insight-caption {
font-family: 'Inter', sans-serif;
font-size: 0.85rem;
color: var(--dvz-text-tertiary);
border-left: 3px solid var(--dvz-cat-1);
padding-left: 12px;
font-style: italic;
}
/* ========================================
Data Table
======================================== */
.dvz-table-wrapper {
overflow-x: auto;
border: 1px solid var(--dvz-border);
border-radius: var(--dvz-card-radius);
background: var(--dvz-surface);
}
.dvz-table {
width: 100%;
border-collapse: collapse;
font-family: 'Inter', sans-serif;
font-size: 0.85rem;
}
.dvz-table thead {
background: var(--dvz-bg);
border-bottom: 2px solid var(--dvz-border);
}
.dvz-table th {
font-family: 'IBM Plex Mono', monospace;
font-weight: 600;
font-size: 0.7rem;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--dvz-text-tertiary);
padding: 12px 16px;
text-align: left;
}
.dvz-table td {
padding: 12px 16px;
border-bottom: 1px solid var(--dvz-border);
color: var(--dvz-text-secondary);
font-variant-numeric: tabular-nums;
}
.dvz-table tbody tr:hover {
background: rgba(49, 130, 206, 0.03);
}
.dvz-table .cell-number {
font-family: 'IBM Plex Mono', monospace;
font-weight: 500;
text-align: right;
}
.dvz-table .cell-positive { color: var(--dvz-positive); }
.dvz-table .cell-negative { color: var(--dvz-negative); }
/* ========================================
Footer
======================================== */
footer {
max-width: var(--dvz-max-width);
margin: 0 auto;
padding: 40px 24px;
border-top: 1px solid var(--dvz-border);
display: flex;
align-items: center;
justify-content: space-between;
font-size: 0.8rem;
color: var(--dvz-text-tertiary);
}
footer a {
color: var(--dvz-text-tertiary);
transition: color 0.2s;
}
footer a:hover { color: var(--dvz-text-primary); }
.footer-links {
display: flex;
gap: 24px;
}
.footer-source {
font-family: 'IBM Plex Mono', monospace;
font-size: 0.7rem;
}
/* ========================================
Responsive
======================================== */
@media (max-width: 1024px) {
.hero {
grid-template-columns: 1fr;
padding: 48px 24px 40px;
gap: 32px;
}
.kpi-row { grid-template-columns: repeat(2, 1fr); }
.dashboard { grid-template-columns: repeat(6, 1fr); }
.chart-card--col-8,
.chart-card--col-4 { grid-column: span 6; }
.insight-section { grid-template-columns: 1fr; gap: 32px; }
}
@media (max-width: 640px) {
nav { padding: 12px 16px; }
nav ul { gap: 16px; }
.hero { padding: 32px 16px 24px; }
.kpi-row {
grid-template-columns: 1fr;
padding: 0 16px 40px;
}
.dashboard {
grid-template-columns: 1fr;
padding: 0 16px 40px;
}
.chart-card--col-8,
.chart-card--col-6,
.chart-card--col-4 { grid-column: span 1; }
.insight-section { padding: 40px 16px; }
footer {
flex-direction: column;
gap: 16px;
text-align: center;
padding: 32px 16px;
}
.footer-links { flex-wrap: wrap; justify-content: center; }
}
</style>
</head>
<body>
<!-- ========================================
Navigation
======================================== -->
<nav>
<a href="#" class="logo">
<span class="logo-mark">
<svg viewBox="0 0 16 16" fill="none">
<path d="M2 12L5 4L8 9L11 2L14 8" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</span>
DataLens
</a>
<ul>
<li><a href="#">Dashboard</a></li>
<li><a href="#">Reports</a></li>
<li><a href="#">Explore</a></li>
<li><a href="#">Docs</a></li>
</ul>
<div class="nav-actions">
<a href="#" class="btn--ghost btn">Log In</a>
<a href="#" class="btn">Get Started</a>
</div>
</nav>
<!-- ========================================
Hero Section
======================================== -->
<section class="hero">
<div class="hero-content">
<div class="hero-eyebrow">Analytics Platform</div>
<h1>See the story your data is telling</h1>
<p class="hero-desc">
Transform raw numbers into beautiful, interactive visualizations
that reveal patterns, trends, and insights at a glance.
</p>
<div class="hero-actions">
<a href="#" class="btn">Start Exploring</a>
<a href="#" class="btn btn--outline">View Examples</a>
</div>
</div>
<div class="hero-chart">
<div class="hero-chart__header">
<span class="hero-chart__title">Revenue Trend</span>
<span class="hero-chart__period">Jan -- Dec 2025</span>
</div>
<svg viewBox="0 0 500 240" fill="none" style="width:100%;height:auto;">
<!-- Gridlines -->
<line x1="40" y1="20" x2="490" y2="20" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="40" y1="65" x2="490" y2="65" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="40" y1="110" x2="490" y2="110" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="40" y1="155" x2="490" y2="155" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="40" y1="200" x2="490" y2="200" stroke="#e2e8f0" stroke-width="0.5"/>
<!-- Y-axis labels -->
<text x="32" y="24" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="end">$50k</text>
<text x="32" y="69" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="end">$40k</text>
<text x="32" y="114" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="end">$30k</text>
<text x="32" y="159" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="end">$20k</text>
<text x="32" y="204" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="end">$10k</text>
<!-- Area fill -->
<path d="M60 170 L100 155 L140 160 L180 130 L220 120 L260 95 L300 100 L340 75 L380 60 L420 45 L460 30 L460 200 L60 200 Z"
fill="url(#areaGrad)" opacity="0.3"/>
<defs>
<linearGradient id="areaGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#3182ce" stop-opacity="0.4"/>
<stop offset="100%" stop-color="#3182ce" stop-opacity="0"/>
</linearGradient>
</defs>
<!-- Data line -->
<polyline points="60,170 100,155 140,160 180,130 220,120 260,95 300,100 340,75 380,60 420,45 460,30"
fill="none" stroke="#3182ce" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<!-- Data points -->
<circle cx="60" cy="170" r="3.5" fill="#fff" stroke="#3182ce" stroke-width="2"/>
<circle cx="140" cy="160" r="3.5" fill="#fff" stroke="#3182ce" stroke-width="2"/>
<circle cx="220" cy="120" r="3.5" fill="#fff" stroke="#3182ce" stroke-width="2"/>
<circle cx="300" cy="100" r="3.5" fill="#fff" stroke="#3182ce" stroke-width="2"/>
<circle cx="380" cy="60" r="3.5" fill="#fff" stroke="#3182ce" stroke-width="2"/>
<circle cx="460" cy="30" r="4" fill="#3182ce" stroke="#fff" stroke-width="2"/>
<!-- Annotation -->
<line x1="460" y1="30" x2="460" y2="50" stroke="#3182ce" stroke-width="1" stroke-dasharray="3,2"/>
<rect x="420" y="52" width="80" height="20" rx="4" fill="#3182ce"/>
<text x="460" y="65" font-family="IBM Plex Mono" font-size="9" fill="#fff" text-anchor="middle">$48.2k peak</text>
<!-- X-axis labels -->
<text x="60" y="218" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="middle">Jan</text>
<text x="140" y="218" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="middle">Mar</text>
<text x="220" y="218" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="middle">May</text>
<text x="300" y="218" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="middle">Jul</text>
<text x="380" y="218" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="middle">Sep</text>
<text x="460" y="218" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="middle">Nov</text>
</svg>
<div style="display:flex;gap:16px;margin-top:12px;">
<span class="legend-item"><span class="legend-swatch" style="background:#3182ce;"></span> Revenue</span>
<span class="legend-item"><span class="legend-swatch" style="background:#e53e3e;"></span> Target</span>
</div>
</div>
</section>
<!-- ========================================
KPI Row
======================================== -->
<section class="kpi-row">
<div class="kpi-card">
<div class="kpi-label">Total Revenue</div>
<div class="kpi-value">$1.24M</div>
<div class="kpi-trend kpi-trend--up">
<svg width="12" height="12" viewBox="0 0 12 12"><path d="M6 2L10 7H2L6 2Z" fill="currentColor"/></svg>
+18.3% YoY
</div>
</div>
<div class="kpi-card">
<div class="kpi-label">Active Users</div>
<div class="kpi-value">34,891</div>
<div class="kpi-trend kpi-trend--up">
<svg width="12" height="12" viewBox="0 0 12 12"><path d="M6 2L10 7H2L6 2Z" fill="currentColor"/></svg>
+7.2% MoM
</div>
</div>
<div class="kpi-card">
<div class="kpi-label">Conversion Rate</div>
<div class="kpi-value">3.8%</div>
<div class="kpi-trend kpi-trend--down">
<svg width="12" height="12" viewBox="0 0 12 12"><path d="M6 10L2 5H10L6 10Z" fill="currentColor"/></svg>
-0.4% MoM
</div>
</div>
<div class="kpi-card">
<div class="kpi-label">Avg. Session</div>
<div class="kpi-value">4m 12s</div>
<div class="kpi-trend kpi-trend--up">
<svg width="12" height="12" viewBox="0 0 12 12"><path d="M6 2L10 7H2L6 2Z" fill="currentColor"/></svg>
+22s vs prev
</div>
</div>
</section>
<!-- ========================================
Dashboard Chart Grid
======================================== -->
<section class="dashboard">
<!-- Main chart: 8-col wide area chart -->
<div class="chart-card chart-card--col-8">
<div class="chart-card__header">
<span class="chart-card__title">User Growth by Channel</span>
<span class="chart-card__meta">Last 12 months</span>
</div>
<div class="chart-card__body">
<svg viewBox="0 0 600 220" fill="none" style="width:100%;height:auto;">
<!-- Grid -->
<line x1="0" y1="0" x2="600" y2="0" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="0" y1="55" x2="600" y2="55" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="0" y1="110" x2="600" y2="110" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="0" y1="165" x2="600" y2="165" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="0" y1="200" x2="600" y2="200" stroke="#e2e8f0" stroke-width="1"/>
<!-- Organic line -->
<polyline points="0,180 50,170 100,155 150,150 200,135 250,120 300,115 350,100 400,85 450,70 500,55 550,40 600,30"
fill="none" stroke="#3182ce" stroke-width="2" stroke-linecap="round"/>
<!-- Paid line -->
<polyline points="0,190 50,185 100,180 150,170 200,165 250,155 300,150 350,140 400,130 450,120 500,115 550,108 600,100"
fill="none" stroke="#319795" stroke-width="2" stroke-linecap="round"/>
<!-- Referral line -->
<polyline points="0,195 50,192 100,188 150,185 200,180 250,178 300,175 350,170 400,165 450,162 500,158 550,155 600,150"
fill="none" stroke="#805ad5" stroke-width="2" stroke-linecap="round"/>
</svg>
</div>
<div class="chart-card__footer">
<div class="chart-card__legend">
<span class="legend-item"><span class="legend-swatch" style="background:#3182ce;"></span> Organic</span>
<span class="legend-item"><span class="legend-swatch" style="background:#319795;"></span> Paid</span>
<span class="legend-item"><span class="legend-swatch" style="background:#805ad5;"></span> Referral</span>
</div>
<span style="margin-left:auto;">Source: Internal Analytics</span>
</div>
</div>
<!-- Side chart: 4-col donut chart -->
<div class="chart-card chart-card--col-4">
<div class="chart-card__header">
<span class="chart-card__title">Traffic Sources</span>
<span class="chart-card__meta">This month</span>
</div>
<div class="chart-card__body">
<svg viewBox="0 0 200 200" fill="none" style="width:180px;height:180px;">
<!-- Donut segments -->
<circle cx="100" cy="100" r="80" fill="none" stroke="#e2e8f0" stroke-width="24"/>
<circle cx="100" cy="100" r="80" fill="none" stroke="#3182ce" stroke-width="24"
stroke-dasharray="201 503" stroke-dashoffset="0"
transform="rotate(-90 100 100)"/>
<circle cx="100" cy="100" r="80" fill="none" stroke="#319795" stroke-width="24"
stroke-dasharray="126 503" stroke-dashoffset="-201"
transform="rotate(-90 100 100)"/>
<circle cx="100" cy="100" r="80" fill="none" stroke="#805ad5" stroke-width="24"
stroke-dasharray="88 503" stroke-dashoffset="-327"
transform="rotate(-90 100 100)"/>
<circle cx="100" cy="100" r="80" fill="none" stroke="#d69e2e" stroke-width="24"
stroke-dasharray="88 503" stroke-dashoffset="-415"
transform="rotate(-90 100 100)"/>
<!-- Center label -->
<text x="100" y="94" font-family="Space Grotesk" font-size="22" font-weight="700" fill="#1b2a4a" text-anchor="middle">34.8k</text>
<text x="100" y="112" font-family="IBM Plex Mono" font-size="9" fill="#718096" text-anchor="middle">TOTAL VISITS</text>
</svg>
</div>
<div class="chart-card__footer">
<div class="chart-card__legend" style="flex-direction:column;gap:8px;">
<span class="legend-item"><span class="legend-swatch" style="background:#3182ce;"></span> Direct (40%)</span>
<span class="legend-item"><span class="legend-swatch" style="background:#319795;"></span> Search (25%)</span>
<span class="legend-item"><span class="legend-swatch" style="background:#805ad5;"></span> Social (18%)</span>
<span class="legend-item"><span class="legend-swatch" style="background:#d69e2e;"></span> Other (17%)</span>
</div>
</div>
</div>
<!-- Bar chart: full width -->
<div class="chart-card chart-card--col-12">
<div class="chart-card__header">
<span class="chart-card__title">Monthly Performance by Region</span>
<span class="chart-card__meta">Q4 2025</span>
</div>
<div class="chart-card__body">
<svg viewBox="0 0 700 180" fill="none" style="width:100%;height:auto;">
<!-- Gridlines -->
<line x1="80" y1="10" x2="690" y2="10" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="80" y1="50" x2="690" y2="50" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="80" y1="90" x2="690" y2="90" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="80" y1="130" x2="690" y2="130" stroke="#e2e8f0" stroke-width="0.5"/>
<line x1="80" y1="160" x2="690" y2="160" stroke="#718096" stroke-width="0.5"/>
<!-- Region labels -->
<text x="75" y="30" font-family="Inter" font-size="11" fill="#4a5568" text-anchor="end">North America</text>
<text x="75" y="70" font-family="Inter" font-size="11" fill="#4a5568" text-anchor="end">Europe</text>
<text x="75" y="110" font-family="Inter" font-size="11" fill="#4a5568" text-anchor="end">Asia Pacific</text>
<text x="75" y="150" font-family="Inter" font-size="11" fill="#4a5568" text-anchor="end">Latin America</text>
<!-- Bars: Oct, Nov, Dec grouped -->
<!-- North America -->
<rect x="85" y="18" width="170" height="10" rx="2" fill="#3182ce"/>
<rect x="85" y="30" width="195" height="10" rx="2" fill="#3182ce" opacity="0.6"/>
<rect x="85" y="42" width="210" height="10" rx="2" fill="#3182ce" opacity="0.35"/>
<!-- Europe -->
<rect x="85" y="58" width="140" height="10" rx="2" fill="#319795"/>
<rect x="85" y="70" width="155" height="10" rx="2" fill="#319795" opacity="0.6"/>
<rect x="85" y="82" width="162" height="10" rx="2" fill="#319795" opacity="0.35"/>
<!-- Asia Pacific -->
<rect x="85" y="98" width="120" height="10" rx="2" fill="#805ad5"/>
<rect x="85" y="110" width="135" height="10" rx="2" fill="#805ad5" opacity="0.6"/>
<rect x="85" y="122" width="150" height="10" rx="2" fill="#805ad5" opacity="0.35"/>
<!-- Latin America -->
<rect x="85" y="138" width="80" height="10" rx="2" fill="#d69e2e"/>
<rect x="85" y="150" width="90" height="10" rx="2" fill="#d69e2e" opacity="0.6"/>
<rect x="85" y="162" width="105" height="10" rx="2" fill="#d69e2e" opacity="0.35"/>
<!-- Values -->
<text x="260" y="26" font-family="IBM Plex Mono" font-size="9" fill="#718096">$420k</text>
<text x="285" y="38" font-family="IBM Plex Mono" font-size="9" fill="#718096">$480k</text>
<text x="300" y="50" font-family="IBM Plex Mono" font-size="9" fill="#718096">$512k</text>
</svg>
</div>
<div class="chart-card__footer">
<div class="chart-card__legend">
<span class="legend-item"><span class="legend-swatch" style="background:#3182ce;"></span> October</span>
<span class="legend-item"><span class="legend-swatch" style="background:#3182ce;opacity:0.6;"></span> November</span>
<span class="legend-item"><span class="legend-swatch" style="background:#3182ce;opacity:0.35;"></span> December</span>
</div>
<span style="margin-left:auto;">Source: Finance Dept.</span>
</div>
</div>
</section>
<!-- ========================================
Insight / Annotation Section
======================================== -->
<section class="insight-section">
<div>
<h2>Key Insight</h2>
<p class="insight-text">
North American revenue accelerated by 22% in Q4, driven by enterprise
adoption. The trendline shows consistent month-over-month growth
since August, outpacing all other regions.
</p>
<p class="insight-caption">
"The data reveals a clear inflection point in September when
the enterprise sales team expanded their outreach program."
</p>
</div>
<div class="chart-card">
<div class="chart-card__header">
<span class="chart-card__title">Regional Comparison</span>
<span class="chart-card__meta">Normalized to Q1 baseline</span>
</div>
<div class="chart-card__body">
<svg viewBox="0 0 400 200" fill="none" style="width:100%;height:auto;">
<line x1="0" y1="100" x2="400" y2="100" stroke="#e2e8f0" stroke-width="0.5" stroke-dasharray="4,4"/>
<text x="395" y="96" font-family="IBM Plex Mono" font-size="8" fill="#718096" text-anchor="end">baseline</text>
<polyline points="0,120 40,115 80,110 120,105 160,100 200,90 240,78 280,65 320,50 360,38 400,25"
fill="none" stroke="#3182ce" stroke-width="2" stroke-linecap="round"/>
<polyline points="0,115 40,112 80,108 120,106 160,102 200,98 240,94 280,90 320,85 360,82 400,78"
fill="none" stroke="#319795" stroke-width="2" stroke-linecap="round"/>
<polyline points="0,110 40,108 80,107 120,108 160,110 200,105 240,100 280,95 320,92 360,88 400,85"
fill="none" stroke="#805ad5" stroke-width="2" stroke-linecap="round" stroke-dasharray="6,3"/>
<!-- Annotation callout -->
<circle cx="200" cy="90" r="12" fill="none" stroke="#3182ce" stroke-width="1" stroke-dasharray="3,2"/>
<text x="218" y="82" font-family="Inter" font-size="9" fill="#3182ce" font-style="italic">inflection point</text>
</svg>
</div>
</div>
</section>
<!-- ========================================
Data Table Section
======================================== -->
<section style="max-width:var(--dvz-max-width);margin:0 auto;padding:0 24px 60px;">
<h2 style="margin-bottom:20px;font-size:1.4rem;">Detailed Breakdown</h2>
<div class="dvz-table-wrapper">
<table class="dvz-table">
<thead>
<tr>
<th>Region</th>
<th>Q3 Revenue</th>
<th>Q4 Revenue</th>
<th>Change</th>
<th>Users</th>
<th>Conversion</th>
</tr>
</thead>
<tbody>
<tr>
<td>North America</td>
<td class="cell-number">$1,012,400</td>
<td class="cell-number">$1,412,000</td>
<td class="cell-number cell-positive">+39.5%</td>
<td class="cell-number">18,420</td>
<td class="cell-number">4.2%</td>
</tr>
<tr>
<td>Europe</td>
<td class="cell-number">$724,800</td>
<td class="cell-number">$857,000</td>
<td class="cell-number cell-positive">+18.2%</td>
<td class="cell-number">9,870</td>
<td class="cell-number">3.6%</td>
</tr>
<tr>
<td>Asia Pacific</td>
<td class="cell-number">$498,200</td>
<td class="cell-number">$635,000</td>
<td class="cell-number cell-positive">+27.5%</td>
<td class="cell-number">12,340</td>
<td class="cell-number">2.9%</td>
</tr>
<tr>
<td>Latin America</td>
<td class="cell-number">$312,600</td>
<td class="cell-number">$275,000</td>
<td class="cell-number cell-negative">-12.0%</td>
<td class="cell-number">4,261</td>
<td class="cell-number">3.1%</td>
</tr>
</tbody>
</table>
</div>
</section>
<!-- ========================================
Footer
======================================== -->
<footer>
<span class="footer-source">Data last updated: 2025-12-31T23:59:00Z</span>
<div class="footer-links">
<a href="#">Methodology</a>
<a href="#">API</a>
<a href="#">Privacy</a>
<a href="#">GitHub</a>
</div>
<span>Built with the Data Viz Art aesthetic</span>
</footer>
</body>
</html>
<title> and <desc> elementsfont-variant-numeric: tabular-nums to any element displaying numbers so that digits align vertically in columns, tables, and changing countersIntersectionObserver to initialize charts only when they scroll into view, keeping initial page load fast and reducing memory usage--dvz-positive and --dvz-negative rather than raw green and red hex codes, so switching to a dark theme or accessible palette requires changing only the variable definitions