diff --git a/apps/web/src/components/analytics/analytics-traffic-chart.tsx b/apps/web/src/components/analytics/analytics-traffic-chart.tsx
index 7567426ea..dd2534c1a 100644
--- a/apps/web/src/components/analytics/analytics-traffic-chart.tsx
+++ b/apps/web/src/components/analytics/analytics-traffic-chart.tsx
@@ -18,6 +18,7 @@ import {
verticalGradient,
type PlotTooltipSeries,
} from "@maple/ui/components/plot"
+import { useMediaQuery } from "@maple/ui/hooks/use-media-query"
import { useTheme } from "@maple/ui/hooks/use-theme"
import { linkedCursorChartProps } from "@/hooks/use-linked-cursor"
@@ -153,6 +154,11 @@ export function AnalyticsTrafficChart({ metric, companion, source, syncId }: Ana
[metric, companion, colors, totals],
)
+ // On a phone the 52px axis gutter is ~15% of the plot; the compact tick labels
+ // ("1.2k", "45s") fit in 36. Viewport rather than container is honest here —
+ // on phones the sidebars are sheets, so the two agree.
+ const narrow = useMediaQuery("max-sm")
+
const definition = useMemo(() => {
const at = (point: TrafficPoint) => point.label
// A bucket one table has and the other doesn't is a gap, not a zero —
@@ -217,12 +223,12 @@ export function AnalyticsTrafficChart({ metric, companion, source, syncId }: Ana
},
},
},
- margin: { left: 52, right: 8, top: 4, bottom: 0 },
+ margin: { left: narrow ? 36 : 52, right: 8, top: 4, bottom: 0 },
focus: "group-x",
focusRing: false,
tooltip: cursorTooltip(focusStore.anchor),
})
- }, [data, painted, gradientPrefix, chromeColors, metric, focusStore])
+ }, [data, painted, gradientPrefix, chromeColors, metric, focusStore, narrow])
// Only when there are two series to tell apart — a lone series is already
// named by the card title, and a legend restating it is one accessory too many.
diff --git a/apps/web/src/components/infra/primitives/stat-rail.tsx b/apps/web/src/components/infra/primitives/stat-rail.tsx
index 6ea2a48ad..34d45bfd2 100644
--- a/apps/web/src/components/infra/primitives/stat-rail.tsx
+++ b/apps/web/src/components/infra/primitives/stat-rail.tsx
@@ -51,6 +51,10 @@ interface StatRailItemProps {
selected?: boolean
/** A tile with nothing to show: still rendered, but not selectable. */
disabled?: boolean
+ /** Extra classes on the tile shell, e.g. container-query padding overrides. */
+ className?: string
+ /** Extra classes on the value, e.g. a container-query size step-down. */
+ valueClassName?: string
}
/**
@@ -78,6 +82,8 @@ export function StatRailItem({
onSelect,
selected,
disabled,
+ className,
+ valueClassName,
}: StatRailItemProps) {
const body = (
<>
@@ -105,6 +111,7 @@ export function StatRailItem({
className={cn(
"shrink-0 whitespace-nowrap font-mono text-[26px] font-semibold tabular-nums leading-none tracking-[-0.01em]",
VALUE_TONE[tone],
+ valueClassName,
)}
>
{value}
@@ -125,7 +132,7 @@ export function StatRailItem({
>
)
- const shell = cn("relative px-5 py-4 animate-in fade-in slide-in-from-bottom-1 duration-500")
+ const shell = cn("relative px-5 py-4 animate-in fade-in slide-in-from-bottom-1 duration-500", className)
const style = delay ? { animationDelay: `${delay}ms`, animationFillMode: "backwards" } : undefined
if (!onSelect) {
diff --git a/apps/web/src/routes/analytics/index.tsx b/apps/web/src/routes/analytics/index.tsx
index 504aa6b80..3ee71c81b 100644
--- a/apps/web/src/routes/analytics/index.tsx
+++ b/apps/web/src/routes/analytics/index.tsx
@@ -367,7 +367,7 @@ function AnalyticsContent({
{Result.builder(breakdownsResult)
.onInitial(() => (
-
+
@@ -522,7 +522,7 @@ function AnalyticsContent({
]
return (
-