# Mobile App Marketing Performance
> One long scrolling page instead of tabs, organised like an editorial spread.
**Marketing · Bold colour · Dark · Single page**
One long scrolling page instead of tabs, organised like an editorial spread. It shows how much a single canvas can carry when the typography does the work.
## What makes it work
- Numbered section rules (01 Trends, 02 Acquisition, 03 Deep dive, 04 Campaign detail) give the scroll a spine.
- Black and lime, with the lime reserved for the numbers that matter.
- Section headers are set much larger than chart titles, so the hierarchy stays obvious when scrolling quickly.
- A useful pattern when your audience reads top to bottom rather than clicking between tabs.
## The views
This dashboard is a single scrolling page, shown in full below.
## See it live
[Open the live dashboard](https://demo4.holistics.io/dashboards/v4/114239-mobile-app-marketing-performance?_pl=58f3c3ed347093b801cdc223) to click through it yourself. No Holistics account needed.
## Theme code
The theme this dashboard actually uses, written out as a reusable `PageTheme`. Paste it into a
`.theme.aml` file under **Development > Library > Themes** to reuse it across your own dashboards,
or inline it as a single dashboard's `theme:` property. Chart colour palettes are set
[separately](/docs/admin/dashboard-themes/color-palettes), so they are not included here.
mobile_app_marketing_theme.theme.aml
```aml
PageTheme mobile_app_marketing_theme {
title: "Ghibli Meadow"
background {
bg_color: "#E5EADF"
bg_image: "linear-gradient(180deg, #7AAD6A 0%, #BCCFAB 30%, #E5D0A0 65%, #D4A878 100%)"
}
canvas {
border {
border_color: "#C7D4A8"
border_width {
top: 2
left: 2
right: 2
bottom: 2
}
border_radius {
top_left: 16
top_right: 16
bottom_left: 16
bottom_right: 16
}
}
shadow: "sm"
background {
bg_color: "rgba(255, 252, 245, 0.88)"
}
}
block {
text {
font_color: "#7A6B54"
font_family: "Arial, sans-serif"
}
label {
font_size: 15
font_color: "#5B7744"
font_family: "Arial Black, Impact, sans-serif"
font_weight: "bold"
}
border {
border_radius {
top_left: 12
top_right: 12
bottom_left: 12
bottom_right: 12
}
}
}
viz {
table {
header {
bg_color: "#E8E0C8"
font_color: "#5B7744"
font_weight: "bold"
}
general {
bg_color: "#FFFCF5"
font_size: 13
font_color: "#5B4A3A"
font_family: "Arial, sans-serif"
hover_color: "#F0EBDA"
banding_color: "#F9F4E8"
grid_color: "#E5DCC4"
border_color: "#D4C9A8"
}
sub_title {
font_size: 11
font_color: "#9A8B70"
}
sub_header {
bg_color: "#F0EBDA"
font_color: "#6B8855"
}
}
}
}
```
The theme is paired with custom CSS, which lives beside it rather than inside it. See
[Custom CSS](/docs/admin/dashboard-themes/custom-css) for where it goes.
Custom CSS
```css
/* ===== Frosted glass canvas ===== */
.h-canvas.dac-canvas {
background: transparent !important;
backdrop-filter: blur(40px) saturate(1.4) !important;
-webkit-backdrop-filter: blur(40px) saturate(1.4) !important;
}
/* Re-apply the tinted overlay as a pseudo so blur shows through */
/* Gradient: transparent edges → opaque middle for readability */
.h-canvas.dac-canvas::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(
180deg,
rgba(255, 252, 245, 0.55) 0%,
rgba(255, 252, 245, 0.92) 12%,
rgba(255, 252, 245, 0.95) 30%,
rgba(255, 252, 245, 0.95) 70%,
rgba(255, 252, 245, 0.92) 88%,
rgba(255, 252, 245, 0.55) 100%
);
border-radius: 16px;
z-index: 0;
pointer-events: none;
}
/* Ensure canvas content stays above the overlay — but not system UI */
.h-canvas.dac-canvas > .h-canvas-item,
.h-canvas.dac-canvas > [class*="block"],
.h-canvas.dac-canvas > [class*="grid"] {
position: relative;
z-index: 1;
}
/* No custom font import needed — using system Arial/Impact */
/* Chart axis labels */
.highcharts-xaxis-labels span,
.highcharts-yaxis-labels span {
color: #7A6B54 !important;
}
/* Chart colors — may conflict with Holistics built-in chart settings. Prefer Holistics UI for better control */
.highcharts-root {
--chart-primary: #7AAC5D;
--chart-secondary: #D4A574;
}
/* Column/Bar series — alternating primary/secondary with 3 tones */
/* KPI styles */
.h-kpi-metric-kpi {
font-family: "Arial Black", Impact, sans-serif;
color: #5B7744;
font-weight: 900;
}
.h-kpi-metric-diff,
.h-kpi-metric-diff *,
.h-kpi-metric-diff .friendly-diff,
.h-kpi-metric-diff span {
font-size: 14px !important;
}
.h-kpi-metric-diff .friendly-diff:not(.negative) {
background: #E8F0E4;
color: #3D6B2E;
border-color: #C7D4A8;
}
.h-kpi-metric-diff .friendly-diff.negative {
background: #F5E0D0;
color: #A05A2C;
border-color: #E0C4A8;
}
/* Control variables */
.h-theme-control-block {
/* Select */
--h-select-bg: #FFFCF5;
--h-select-text: #5B4A3A;
--h-select-border: #D4C9A8;
--h-select-border-hover: #B8AA88;
--h-select-border-focus: #7AAC5D;
/* Input */
--h-input-bg: #FFFCF5;
--h-input-text-color: #5B4A3A;
--h-input-border: #D4C9A8;
--h-input-border-hover: #B8AA88;
--h-input-border-focus: #7AAC5D;
/* Badge */
--h-badge-bg: #F0EBDA;
--h-badge-text: #5B7744;
--h-badge-border: #C7D4A8;
--h-badge-hover-bg: #E8E0C8;
/* Checkbox */
--h-checkbox-checked-bg: #7AAC5D;
--h-checkbox-checked-border: #5B7744;
}
/* Standalone controls + date filter form container */
.dac-ic-block .hui-select-trigger,
.dac-ic-block .h-input,
.h-theme-control-block .h-theme-dm-filter-container .dm-filter-form {
border-radius: 14px;
}
/* PoP operator select — left edge rounded */
.dac-ic-block .pop-condition-select__operator-select {
border-radius: 0;
border-top-left-radius: 14px;
border-bottom-left-radius: 14px;
}
/* PoP number input — no radius (middle element) */
.dac-ic-block .pop-condition-select__offset-input {
border-radius: 0;
}
/* PoP period select — right edge rounded */
.dac-ic-block .pop-condition-select__period-select {
border-radius: 0;
border-top-right-radius: 14px;
border-bottom-right-radius: 14px;
}
/* Date filter mark — synced with badge */
.h-highlightable-input mark {
background-color: #F0EBDA;
color: #5B7744;
border: 1px solid #C7D4A8;
}
/* Pivot total row */
.ag-floating-bottom .ag-cell {
background-color: #E8E0C8;
}
.ag-floating-bottom .ag-cell:not(.h-following-span) {
color: #5B7744;
}
/* Metric sheet sparkline */
.h-chart-cell {
--h-table-sparkline-color: #7AAC5D;
}
/* ===== Brutalist accent overlays ===== */
/* KPI card — overlay border with left accent stripe */
.h-kpi-metric {
position: relative;
border: none;
border-radius: 12px;
box-shadow: inset 0 0 0 3px #000;
padding: 36px 16px 20px 20px;
margin-top: 16px;
height: calc(100% - 16px);
box-sizing: border-box;
border-left: 6px solid #A8C846 !important;
}
/* KPI label — black slab overlapping the border */
.h-kpi-metric-label {
position: absolute;
top: -14px;
left: 8px;
right: 8px;
background: #000;
color: #A8C846 !important;
font-family: "Arial Black", Impact, sans-serif !important;
font-size: 12px !important;
font-weight: 900 !important;
text-transform: uppercase;
letter-spacing: 1px;
padding: 4px 10px;
border-radius: 4px;
z-index: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: fit-content;
max-width: calc(100% - 16px);
transition: transform 0.3s ease-out, padding-left 0.3s ease-out;
}
/* KPI label — # prefix that slides in on hover */
.h-kpi-metric-label::before {
content: '#';
display: inline-block;
width: 0;
overflow: hidden;
color: #fff;
font-size: 20px !important;
font-family: "Arial Black", Impact, sans-serif !important;
font-weight: 900;
letter-spacing: 0;
vertical-align: -6px;
white-space: nowrap;
transform: rotate(-8deg);
transition: width 0.3s ease-out;
margin-right: -2px;
}
/* KPI label — scanline overlay */
.h-kpi-metric-label::after {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: repeating-linear-gradient(
0deg, transparent, transparent 2px,
rgba(255, 255, 255, 0.15) 2px, rgba(255, 255, 255, 0.15) 4px
);
background-size: 100% 4px;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s;
}
.h-kpi-metric:hover .h-kpi-metric-label::after {
opacity: 1;
animation: scanline-scroll 4s linear infinite;
}
/* KPI card hover — zoom label + show # */
.h-kpi-metric:hover .h-kpi-metric-label {
transform: scale(1.06);
transform-origin: left center;
}
.h-kpi-metric:hover .h-kpi-metric-label::before {
width: 18px;
}
/* KPI number — brush highlight effect, bigger for wider cards */
.h-kpi-metric-kpi {
font-size: 28px !important;
background: linear-gradient(180deg, transparent 55%, rgba(168, 200, 70, 0.3) 55%, rgba(168, 200, 70, 0.3) 85%, transparent 85%);
display: inline;
padding: 0 6px;
}
/* ===== Chart/widget block titles — brush underline accent ===== */
.dac-viz-block-label {
color: #1a1a1a !important;
font-family: "Arial Black", Impact, sans-serif !important;
font-size: 14px !important;
font-weight: 900 !important;
text-transform: uppercase;
letter-spacing: 1px;
padding: 2px 4px !important;
position: relative;
background: transparent !important;
transition: transform 0.3s ease-out, text-shadow 0.3s ease-out;
}
/* Underline as pseudo — enables wipe animation */
.dac-viz-block-label::after {
content: '';
position: absolute;
left: 4px; right: 4px;
bottom: 0; height: 40%;
background: rgba(168, 200, 70, 0.4);
z-index: -1;
transition: width 0.4s ease-out, background 0.3s ease-out;
}
/* # prefix — hidden by default */
.dac-viz-block-label::before {
content: '#';
display: inline-block;
width: 0;
overflow: hidden;
color: #5B7744;
font-size: 26px !important;
font-family: "Arial Black", Impact, sans-serif !important;
font-weight: 900;
vertical-align: middle;
white-space: nowrap;
transform: rotate(-12deg);
transition: width 0.3s ease-out;
margin-right: 0px;
}
/* Hover on block — wipe underline + show # + lift + glow */
.dac-viz-block:hover .dac-viz-block-label {
transform: translateY(-1px);
text-shadow: 0 0 6px rgba(168, 200, 70, 0.3);
}
.dac-viz-block:hover .dac-viz-block-label::after {
background: rgba(168, 200, 70, 0.6);
}
.dac-viz-block:hover .dac-viz-block-label::before {
width: 22px;
}
/* ===== Section divider hover effects ===== */
.sec-bar {
transition: box-shadow 0.3s ease-out;
cursor: default;
position: relative;
overflow: hidden;
}
.sec-bar:hover {
box-shadow: 0 0 14px rgba(168, 200, 70, 0.4), inset 0 0 20px rgba(168, 200, 70, 0.06);
}
/* CRT scanline overlay on section bar */
.sec-bar::after {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: repeating-linear-gradient(
0deg, transparent, transparent 2px,
rgba(0, 0, 0, 0.12) 2px, rgba(0, 0, 0, 0.12) 4px
);
background-size: 100% 4px;
pointer-events: none;
opacity: 0;
z-index: 1;
transition: opacity 0.3s;
}
.sec-bar:hover::after {
opacity: 1;
animation: scanline-scroll 4s linear infinite;
}
@keyframes scanline-scroll {
0% { background-position: 0 0; }
100% { background-position: 0 200px; }
}
/* Badge pop + rotate */
.sec-num {
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
display: inline-block;
position: relative;
margin-right: 4px;
}
.sec-bar:hover .sec-num {
transform: scale(1.3) rotate(-8deg);
}
/* # on badge — opacity fade in on hover */
.sec-num::before {
content: '#';
font-size: 16px !important;
font-family: "Arial Black", Impact, sans-serif !important;
font-weight: 900;
color: #2D4A1E;
opacity: 0;
display: inline;
margin-right: -8px;
transition: opacity 0.3s ease-out, margin-right 0.3s ease-out;
}
.sec-bar:hover .sec-num::before {
opacity: 1;
margin-right: 1px;
}
/* Title — glitch scramble on hover */
@keyframes sec-glitch {
0% { opacity: 1; transform: translate(0,0) skewX(0deg); }
5% { opacity: 0.8; transform: translate(2px,-1px) skewX(-3deg); }
10% { opacity: 1; transform: translate(-1px,1px) skewX(2deg); }
15% { opacity: 0.9; transform: translate(1px,0px) skewX(-1deg); }
20% { opacity: 1; transform: translate(0,0) skewX(0deg); }
100% { opacity: 1; transform: translate(0,0) skewX(0deg); }
}
.sec-title {
display: inline-block;
transition: text-shadow 0.3s ease-out;
}
.sec-bar:hover .sec-title {
text-shadow: 0 0 8px rgba(168, 200, 70, 0.6);
animation: sec-glitch 2s steps(1) infinite;
}
/* Subtitle slide in */
.sec-sub {
transition: opacity 0.3s ease-out, transform 0.3s ease-out;
opacity: 0.6;
}
.sec-bar:hover .sec-sub {
opacity: 1;
transform: translateX(4px);
}
/* ===== Filter blocks ===== */
.dac-ic-block {
background: transparent !important;
border: none !important;
}
/* Filter labels — brush underline same as chart titles */
.dac-ic-block-label {
background: transparent !important;
color: #1a1a1a !important;
font-family: "Arial Black", Impact, sans-serif !important;
font-size: 11px !important;
font-weight: 900 !important;
text-transform: uppercase;
letter-spacing: 1px;
padding: 1px 3px !important;
border: none !important;
margin-bottom: 6px !important;
background-image: linear-gradient(180deg, transparent 60%, rgba(168, 200, 70, 0.4) 60%) !important;
}
/* Hide the link/chain icon next to filter labels */
.dac-ic-block .h-icon-link,
.dac-ic-block .dac-block-label-container .h-icon,
.dac-ic-block .dac-block-label-container svg {
display: none !important;
}
/* Filter inputs — neutral, no green */
.dac-ic-block .hui-select-trigger,
.dac-ic-block .h-input {
background: #FFFCF5 !important;
border: 1px solid #D4C9A8 !important;
border-radius: 4px !important;
color: #5B4A3A !important;
font-family: "Arial", sans-serif !important;
font-size: 13px !important;
}
.dac-ic-block .hui-select-trigger:hover,
.dac-ic-block .h-input:hover {
border-color: #B8AA88 !important;
}
.dac-ic-block .hui-select-trigger:focus-within,
.dac-ic-block .h-input:focus {
border-color: #7A6B54 !important;
}
/* Date filter form */
.dac-ic-block .dm-filter-form {
border-radius: 4px !important;
}
```