/* ===========================================================================
   Core Forms Design System - dashboard extension
   ===========================================================================

   The Core Forms Design System is a marketing-site system. It has buttons,
   nav, cards, sections, pricing, FAQ and prose, but no application shell, no
   data grid, no generic form field, no pagination, no empty state and no chart
   colours. This layer adds exactly those, written only in CFDS tokens so the
   two files stay one design language.

   Rules for anything added here:
     - Use CFDS custom properties. No raw hex, no invented spacing scale
       beyond the --gap-* below (CFDS ships no spacing tokens).
     - Prefer generalising an existing CFDS component to inventing a new one.
     - No !important.

   CFDS is light-only and roughly a dozen of its component rules hardcode
   background:#fff, so a dark theme is a deliberate non-goal here rather than
   an oversight.
   ========================================================================= */

:root {
    /* Wider than the CFDS default of 1180px.
       Overridden here rather than edited in core-forms.css: that file is
       vendored verbatim from the design system repo, and patching it would
       have to be redone by hand on every update. */
    --container: 1600px;

    /* CFDS has no spacing scale. These are the only additions, kept small
       and named so they read as a system rather than magic numbers. */
    --gap-xs: 6px;
    --gap-sm: 10px;
    --gap-md: 16px;
    --gap-lg: 24px;
    --gap-xl: 36px;

    /* Categorical series colours. CFDS gives a 10-step sequential brand ramp
       but nothing for "these are different things". Ordered so the first two
       carry the most common pairing (views vs visitors) and stay
       distinguishable in the common forms of colour blindness. */
    --series-1: var(--brand-500);
    --series-2: #0f9d8f;
    --series-3: #b8631a;
    --series-4: #7a4bd0;
    --series-5: #2f7d31;
    --series-6: #b03060;

    --meter-track: var(--ink-100);
    --meter-fill: var(--brand-200);
}

/* --------------------------------------------------------------------------
   App shell
   -------------------------------------------------------------------------- */

.app-shell {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--gap-lg);
    align-items: start;
}

@media (min-width: 960px) {
    .app-shell {
        grid-template-columns: 210px minmax(0, 1fr);
        gap: var(--gap-xl);
    }
}

/* Signed-out pages have no sidebar. Explicitly collapse the desktop shell to
   one column so the main content cannot fall into the 210px navigation track. */
.app-shell--auth {
    grid-template-columns: minmax(0, 1fr);
}

.app-main {
    /* CFDS .nav is position:sticky at a hardcoded 68px. */
    padding-block: var(--gap-lg) var(--gap-xl);
    min-height: calc(100vh - 68px);
    /* Grid child: without this a wide table refuses to shrink and pushes the
       page into horizontal scroll instead of scrolling inside .table-wrap. */
    min-width: 0;
}

.app-main--auth {
    display: flex;
    justify-content: center;
}

/* Every band of a page is separated by the same gap, whatever it is made of --
   a KPI row, a card, a grid of cards, a form. One rule instead of a growing
   list of sibling combinations. */
.app-main > * + * {
    margin-block-start: var(--gap-md);
}

/* The page title earns a larger break than the bands below it. */
.app-main > .app-head + * {
    margin-block-start: var(--gap-lg);
}

/* CFDS hides .nav-links below 860px because its marketing nav expects the
   hamburger and slide-down panel. This app has two links, so showing them is
   simpler and cheaper than shipping the JS that panel needs -- and leaving
   them hidden strands mobile users with no navigation at all. */
@media (max-width: 859px) {
    .nav .nav-links {
        display: flex;
        gap: var(--gap-md);
        font-size: 0.92rem;
    }

    .nav .nav-inner {
        gap: var(--gap-sm);
    }
}

.app-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--gap-md);
}

.app-head h1 {
    margin: 0;
    font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2rem);
}

.app-head p {
    margin: var(--gap-xs) 0 0;
    color: var(--ink-600);
    font-size: 0.95rem;
}

.app-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--gap-sm);
    align-items: center;
}

/* --------------------------------------------------------------------------
   Sidebar: navigation and saved views.
   -------------------------------------------------------------------------- */

.sidebar {
    display: flex;
    flex-direction: column;
    gap: var(--gap-lg);
    padding-block: var(--gap-lg);
}

@media (min-width: 960px) {
    .sidebar {
        position: sticky;
        /* Clears the 68px sticky nav. */
        top: calc(68px + var(--gap-lg));
        max-height: calc(100vh - 68px - var(--gap-lg) * 2);
        overflow-y: auto;
    }
}

.sidebar__group {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.sidebar__label {
    margin: 0 0 var(--gap-xs);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-400);
}

.sidebar__empty {
    margin: 0;
    font-size: 0.78rem;
    color: var(--ink-500);
    line-height: 1.5;
}

.sidebar__link {
    display: flex;
    align-items: center;
    gap: var(--gap-sm);
    padding: 7px var(--gap-sm);
    border-radius: var(--r-md);
    font-size: 0.88rem;
    color: var(--ink-700);
    text-decoration: none;
    white-space: nowrap;
    transition:
        background var(--t-fast),
        color var(--t-fast);
}

.sidebar__link .icon {
    color: var(--ink-400);
}

.sidebar__link:hover {
    background: var(--bg-soft);
    color: var(--ink-900);
}

.sidebar__link.is-active,
.sidebar__preset.is-active .sidebar__link {
    background: var(--brand-50);
    color: var(--brand-700);
    font-weight: 600;
}

.sidebar__link.is-active .icon,
.sidebar__preset.is-active .sidebar__link .icon {
    color: var(--brand-500);
}

.sidebar__preset {
    display: flex;
    align-items: center;
    gap: 2px;
}

.sidebar__preset .sidebar__link {
    flex: 1;
    min-width: 0;
}

.sidebar__preset .sidebar__link span {
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar__remove {
    flex: none;
    inline-size: 22px;
    block-size: 22px;
    border: 0;
    border-radius: var(--r-sm);
    background: none;
    color: var(--ink-300);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    /* Revealed on hover or keyboard focus -- a delete control on every row
       would compete with the label it sits beside. */
    opacity: 0;
    transition:
        opacity var(--t-fast),
        color var(--t-fast);
}

.sidebar__preset:hover .sidebar__remove,
.sidebar__remove:focus-visible {
    opacity: 1;
}

.sidebar__remove:hover {
    color: var(--danger-500);
    background: var(--ink-100);
}

.sidebar__add {
    display: flex;
    align-items: center;
    gap: var(--gap-sm);
    margin-block-start: var(--gap-xs);
    padding: 7px var(--gap-sm);
    border: 1px dashed var(--ink-200);
    border-radius: var(--r-md);
    background: none;
    font: inherit;
    font-size: 0.82rem;
    color: var(--ink-500);
    cursor: pointer;
    white-space: nowrap;
}

.sidebar__add:hover {
    border-color: var(--brand-200);
    color: var(--brand-600);
}

.sidebar__save {
    display: flex;
    flex-direction: column;
    gap: var(--gap-xs);
    margin-block-start: var(--gap-xs);
}

.sidebar__save .input {
    font-size: 0.85rem;
    padding: 7px var(--gap-sm);
}

.sidebar__save-actions {
    display: flex;
    gap: var(--gap-xs);
}

/* Below the shell breakpoint the sidebar becomes one compact, horizontally
   scrollable row. Keep this after the base group rules: placing it before
   `.sidebar__group` let the base column direction win in the cascade, which
   turned the mobile navigation into three tall columns. */
@media (max-width: 959px) {
    .sidebar {
        flex-direction: row;
        gap: var(--gap-md);
        overflow-x: auto;
        overscroll-behavior-inline: contain;
        scrollbar-width: thin;
        padding-block: var(--gap-sm);
        border-block-end: 1px solid var(--ink-100);
    }

    .sidebar__group {
        flex: none;
        flex-direction: row;
        align-items: center;
        gap: var(--gap-xs);
    }

    .sidebar__label,
    .sidebar__empty {
        display: none;
    }

    .sidebar__preset,
    .sidebar__preset .sidebar__link,
    .sidebar__add {
        flex: none;
    }

    .sidebar__add {
        margin-block-start: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .sidebar__link,
    .sidebar__remove {
        transition: none;
    }
}

/* --------------------------------------------------------------------------
   Icons. Lucide React SVGs inherit colour from their parent.
   -------------------------------------------------------------------------- */

.icon {
    display: inline-block;
    flex: none;
    vertical-align: -0.125em;
}

/* Nav links carry a leading icon; keep the pair on one baseline. */
.nav .nav-links a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.nav .nav-links a .icon {
    color: var(--ink-400);
}

.nav .nav-links a.is-active .icon {
    color: var(--brand-500);
}

/* The mark picks up the brand colour; the wordmark stays ink. */
.nav-brand .logo {
    color: var(--brand-500);
    flex: none;
}

.icon--inline {
    color: var(--ink-400);
    margin-inline-end: 2px;
}

/* --------------------------------------------------------------------------
   Real-time
   -------------------------------------------------------------------------- */

.live-pill {
    gap: var(--gap-xs);
}

.live-dot {
    inline-size: 7px;
    block-size: 7px;
    border-radius: var(--r-full);
    background: currentColor;
    animation: live-pulse 2s ease-in-out infinite;
}

@keyframes live-pulse {
    0%,
    100% {
        opacity: 1;
    }
    50% {
        opacity: 0.25;
    }
}

@media (prefers-reduced-motion: reduce) {
    .live-dot {
        animation: none;
    }
}

.kpi__icon {
    display: block;
    color: var(--ink-400);
    margin-block-end: var(--gap-xs);
}

.kpi--primary .kpi__icon {
    color: var(--brand-400);
}

.kpi__hint {
    display: block;
    margin-block-start: var(--gap-xs);
    font-size: 0.72rem;
    color: var(--ink-500);
}

/* Per-minute activity. Bars scale off --h (0..1) rather than a fixed height,
   so an empty minute is a visible gap instead of a missing column. */
.sparkline {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    block-size: 80px;
}

.sparkline__bar {
    flex: 1;
    min-inline-size: 3px;
    block-size: calc(max(var(--h, 0) * 100%, 2px));
    background: var(--brand-300);
    border-radius: var(--r-xs) var(--r-xs) 0 0;
    transition: block-size var(--t-med);
}

.sparkline__bar:last-child {
    background: var(--brand-500);
}

@media (prefers-reduced-motion: reduce) {
    .sparkline__bar {
        transition: none;
    }
}

/* Live feed */
.feed {
    margin: 0;
    padding: 0;
    list-style: none;
}

.feed__item {
    display: grid;
    grid-template-columns: 20px minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--gap-sm);
    padding: var(--gap-xs) var(--gap-md);
    border-block-end: 1px solid var(--ink-100);
    font-size: 0.88rem;
}

@media (min-width: 760px) {
    .feed__item {
        grid-template-columns: 20px minmax(0, 1fr) 160px 40px 48px;
    }
}

.feed__item:last-child {
    border-block-end: 0;
}

.feed__item--conversion {
    background: var(--brand-50);
}

.feed__icon {
    color: var(--ink-400);
    display: flex;
}

.feed__item--conversion .feed__icon {
    color: var(--brand-600);
}

.feed__main a {
    color: var(--ink-900);
    text-decoration: none;
}

.feed__main a:hover {
    color: var(--brand-600);
    text-decoration: underline;
}

.feed__meta {
    font-size: 0.78rem;
    color: var(--ink-500);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Secondary columns would crowd a phone; the path and age carry the meaning. */
@media (max-width: 759px) {
    .feed__meta {
        display: none;
    }
}

.feed__time {
    font-size: 0.76rem;
    color: var(--ink-400);
    font-variant-numeric: tabular-nums;
    text-align: end;
}

/* --------------------------------------------------------------------------
   Code block with a copy button. CFDS styles <pre> inside .prose-article
   only, and this needs a header row regardless.
   -------------------------------------------------------------------------- */

.codeblock {
    border: 1px solid var(--ink-200);
    border-radius: var(--r-md);
    overflow: hidden;
    background: var(--bg-alt);
}

.codeblock__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--gap-md);
    padding: var(--gap-xs) var(--gap-xs) var(--gap-xs) var(--gap-md);
    border-block-end: 1px solid var(--ink-200);
}

.codeblock__label {
    font-size: 0.76rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-500);
}

.codeblock__code {
    margin: 0;
    padding: var(--gap-md);
    overflow-x: auto;
    background: var(--bg);
    font-family: var(--font-mono);
    font-size: 0.82rem;
    line-height: 1.6;
    color: var(--ink-800);
    tab-size: 2;
}

.codeblock__code code {
    background: none;
    padding: 0;
    font: inherit;
    color: inherit;
    white-space: pre;
}

/* Sign-in: a single centred card, no nav chrome around it. */
.signin {
    width: min(100%, 440px);
    max-width: 440px;
    margin-inline: auto;
    margin-block-start: clamp(var(--gap-lg), 8vh, 96px);
}

.signin__head {
    margin-block-end: var(--gap-lg);
    text-align: center;
}

.signin__head h1 {
    margin-block: var(--gap-xs) var(--gap-sm);
    font-size: 1.75rem;
}

.signin__head p {
    margin: 0;
    color: var(--ink-600);
    font-size: 0.95rem;
}

.signin__divider {
    display: flex;
    align-items: center;
    gap: var(--gap-sm);
    margin-block: var(--gap-md);
    color: var(--ink-400);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.signin__divider::before,
.signin__divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--ink-200);
}

.signin__invite {
    margin: var(--gap-md) 0 0;
    color: var(--ink-500);
    font-size: 0.82rem;
    line-height: 1.55;
    text-align: center;
}

.signin .btn {
    min-height: 46px;
    white-space: normal;
}

@media (max-width: 560px) {
    .app-main--auth {
        padding-block-start: var(--gap-sm);
    }

    .signin {
        margin-block-start: var(--gap-md);
        padding-inline: 0;
    }

    .signin .card-body {
        padding: var(--gap-md);
    }
}

/* --------------------------------------------------------------------------
   Card - CFDS has feature-card, plugin-card, download-card and so on, but no
   generic container. This is that idiom extracted.
   -------------------------------------------------------------------------- */

.card {
    background: var(--bg);
    border: 1px solid var(--ink-200);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-xs);
}

/* Card spacing is owned by the page flow (.app-main > * + *), not by the card
   itself. Scoping it to `.card + .card` only ever spaced two adjacent cards --
   a .kpis row followed by a card, or two .grid-cards in a row, sat flush
   against each other, which is exactly what went wrong on the realtime and
   settings pages. */

.card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--gap-md);
    padding: var(--gap-md) var(--gap-lg);
    border-block-end: 1px solid var(--ink-100);
}

.card-head h2,
.card-head h3 {
    margin: 0;
    font-family: var(--font-sans);
    font-size: 0.95rem;
    font-weight: 650;
    letter-spacing: 0;
    color: var(--ink-800);
}

.card-head__link {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--brand-600);
    text-decoration: none;
    white-space: nowrap;
}

.card-head__link:hover {
    text-decoration: underline;
}

.card-body {
    padding: var(--gap-lg);
}

.card-body--flush {
    padding: 0;
}

.grid-cards {
    display: grid;
    gap: var(--gap-md);
    grid-template-columns: 1fr;
}

/* Grid items default to min-width:auto, so a wide data table refuses to
   shrink and pushes the whole page into horizontal scroll instead of
   scrolling inside its own .table-wrap. Overriding to 0 lets the wrapper do
   its job. */
.grid-cards > * {
    min-width: 0;
}

@media (min-width: 760px) {
    .grid-cards--2 {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 960px) {
    .grid-cards--3 {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* Dashboard stack: every direct child is a band of the report. */
.dashboard > * + * {
    margin-block-start: var(--gap-md);
}

.dashboard.is-busy {
    opacity: 0.6;
    transition: opacity var(--t-fast);
}

/* The chart needs a fixed block size for recharts' ResponsiveContainer to
   have something to fill, and less inline padding than a normal card body so
   the plot reaches closer to the edges. */
.chart-body {
    block-size: 300px;
    padding-inline: var(--gap-sm);
    padding-block-end: var(--gap-sm);
}

.chart-tooltip {
    background: var(--bg);
    border: 1px solid var(--ink-200);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-md);
    padding: var(--gap-sm) var(--gap-md);
    font-size: 0.85rem;
}

.chart-tooltip__date {
    font-weight: 650;
    color: var(--ink-900);
    margin-block-end: var(--gap-xs);
}

.chart-tooltip__list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 2px;
    color: var(--ink-700);
}

.chart-tooltip__list li {
    display: flex;
    align-items: center;
    gap: var(--gap-xs);
    font-variant-numeric: tabular-nums;
}

.chart-tooltip__swatch {
    inline-size: 8px;
    block-size: 8px;
    border-radius: var(--r-full);
    flex: none;
}

/* Standalone message pages (404, dashboard error boundary). */
.errorbox {
    margin-block-start: clamp(var(--gap-lg), 6vh, 64px);
}

.errorbox__head {
    text-align: start;
    margin-block-end: var(--gap-md);
}

.errorbox__head h1 {
    margin-block: var(--gap-xs) var(--gap-xs);
    font-size: 1.5rem;
}

.errorbox__head p {
    margin: 0;
    color: var(--ink-600);
}

.errorbox__context {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--gap-xs) var(--gap-md);
    margin: var(--gap-md) 0 0;
    font-size: 0.88rem;
}

.errorbox__context dt {
    color: var(--ink-500);
}

.errorbox__context dd {
    margin: 0;
    color: var(--ink-800);
}

/* --------------------------------------------------------------------------
   Data table
   CFDS styles tables only inside .prose-article. This is the application
   variant: hoverable rows, sticky header, sortable headers, numeric columns.
   -------------------------------------------------------------------------- */

.table-wrap {
    overflow-x: auto;
    border-radius: var(--r-lg);
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.92rem;
    line-height: 1.5;
}

.data-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--bg-alt);
    color: var(--ink-700);
    font-family: var(--font-sans);
    font-weight: 650;
    font-size: 0.78rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-align: left;
    padding: var(--gap-sm) var(--gap-md);
    border-block-end: 1px solid var(--ink-200);
    white-space: nowrap;
}

.data-table tbody td {
    padding: var(--gap-sm) var(--gap-md);
    border-block-end: 1px solid var(--ink-100);
    color: var(--ink-700);
    vertical-align: middle;
}

.data-table tbody tr:last-child td {
    border-block-end: 0;
}

.data-table tbody tr:hover td {
    background: var(--bg-soft);
}

/* Numbers line up only if they are right-aligned and tabular. */
.data-table .num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--ink-800);
}

.data-table .col-main {
    width: 100%;
    min-width: 220px;
}

.data-table--dense tbody td,
.data-table--dense thead th {
    padding-block: var(--gap-xs);
}

.data-table a {
    color: var(--ink-900);
    text-decoration: none;
}

.data-table a:hover {
    color: var(--brand-600);
    text-decoration: underline;
}

.cell-stack {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.cell-sub {
    font-size: 0.78rem;
    color: var(--ink-500);
}

.cell-actions {
    display: flex;
    gap: var(--gap-xs);
    justify-content: flex-end;
    white-space: nowrap;
}

/* Row label: an inline share bar behind the text, the label itself (which may
   filter the dashboard), and an open-in-new-tab affordance. */

.row-label {
    position: relative;
    display: flex;
    align-items: center;
    min-height: 24px;
}

.row-label__bar {
    position: absolute;
    inset-block: -2px;
    inset-inline-start: calc(var(--gap-md) * -1);
    /* Scales from the row's own share of the visible page. */
    inline-size: calc((100% + var(--gap-md) * 2) * var(--pct, 0));
    background: var(--brand-50);
    border-radius: var(--r-xs);
    pointer-events: none;
}

.row-label__content {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--gap-xs);
    min-width: 0;
    max-width: 100%;
}

.row-label__icon {
    inline-size: 16px;
    block-size: 16px;
    flex: none;
    border-radius: var(--r-full);
    background: var(--bg);
}

.row-label__filter {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: var(--ink-800);
    text-align: start;
    cursor: pointer;
    max-width: 40ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.row-label__filter:hover {
    color: var(--brand-600);
    text-decoration: underline;
}

.row-label__open {
    display: inline-flex;
    flex: none;
    color: var(--ink-400);
    transition: color var(--t-fast);
}

.row-label__open:hover {
    color: var(--brand-600);
}

/* Grouped referrer source, expandable to its exact URLs. */
.source__summary {
    display: flex;
    align-items: center;
    gap: var(--gap-xs);
    cursor: pointer;
    list-style: none;
    padding-block: 2px;
}

.source__summary::-webkit-details-marker {
    display: none;
}

.source__caret {
    inline-size: 0;
    block-size: 0;
    flex: none;
    border-inline-start: 4px solid var(--ink-400);
    border-block: 3.5px solid transparent;
    transition: transform var(--t-fast);
}

.source[open] .source__caret {
    transform: rotate(90deg);
}

.source__summary:hover .source__caret {
    border-inline-start-color: var(--brand-500);
}

.source__name {
    font-weight: 550;
    color: var(--ink-800);
}

.source__summary:hover .source__name {
    color: var(--brand-600);
}

.conversion-detail__summary {
    display: flex;
    align-items: center;
    gap: var(--gap-xs);
    cursor: pointer;
    list-style: none;
}

.conversion-detail__summary::-webkit-details-marker {
    display: none;
}

.conversion-detail[open] .source__caret {
    transform: rotate(90deg);
}

.conversion-detail__summary:hover .source__name {
    color: var(--brand-600);
}

.conversion-detail__list {
    display: flex;
    flex-direction: column;
    gap: var(--gap-xs);
    margin: var(--gap-sm) 0 var(--gap-xs);
    padding: var(--gap-sm);
    list-style: none;
    border: 1px solid var(--border, #e2e8f0);
    border-radius: var(--r-sm);
    background: var(--surface-subtle, #f8fafc);
}

.conversion-detail__list li {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--gap-md);
}

.conversion-detail__context,
.conversion-detail__totals {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.conversion-detail__context small {
    display: flex;
    align-items: center;
    gap: 3px;
    color: var(--ink-500);
    white-space: normal;
}

.conversion-detail__totals {
    flex: none;
    align-items: flex-end;
    font-variant-numeric: tabular-nums;
}

.conversion-detail__totals small {
    color: var(--ink-500);
}

.source__count {
    font-size: 0.72rem;
    color: var(--ink-400);
    white-space: nowrap;
}

.source__urls {
    margin: var(--gap-xs) 0 var(--gap-xs);
    /* Indent to the caret, so children read as belonging to the source. */
    padding-inline-start: calc(var(--gap-xs) + 18px);
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.source__urls li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--gap-sm);
    font-size: 0.8rem;
}

.source__url-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/* A button, so it reads as "narrow the report", not "leave the site". */
.source__url {
    padding: 0;
    font: inherit;
    color: var(--ink-600);
    text-align: start;
    background: none;
    border: 0;
    cursor: pointer;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.source__url:hover {
    color: var(--brand-600);
    text-decoration: underline;
}

.source__url:focus-visible {
    outline: 2px solid var(--brand-400);
    outline-offset: 2px;
    border-radius: var(--r-xs);
}

.source__url-count {
    flex: none;
    color: var(--ink-400);
    font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
    .source__caret {
        transition: none;
    }
}

/* Loading cards dim rather than collapse, so the layout does not jump. */
.card.is-busy {
    opacity: 0.6;
    transition: opacity var(--t-fast);
}

/* Active filter pills. */
.filter-badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--gap-xs);
}

.filter-badge {
    text-transform: none;
    letter-spacing: 0;
    gap: var(--gap-xs);
    padding-inline-end: var(--gap-xs);
}

.filter-badge__key {
    opacity: 0.7;
}

.filter-badge__key::after {
    content: ":";
}

.filter-badge__value {
    font-weight: 700;
    /* A referrer filter is a whole URL, which would otherwise push the badge
       past the width of the toolbar. */
    max-width: 32ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.filter-badge__remove {
    display: inline-flex;
    align-items: center;
    padding: 2px;
    border: 0;
    border-radius: var(--r-full);
    background: none;
    color: inherit;
    cursor: pointer;
}

.filter-badge__remove:hover {
    background: var(--brand-100);
}

/* --------------------------------------------------------------------------
   Meter - CFDS's only bar is .tour-progress__bar, a 6.5s autoplay animation.
   This is the determinate version, driven by --pct.
   -------------------------------------------------------------------------- */

.meter {
    position: relative;
    height: 4px;
    border-radius: var(--r-full);
    background: var(--meter-track);
    overflow: hidden;
}

.meter__bar {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: var(--meter-fill);
    transform-origin: left center;
    transform: scaleX(var(--pct, 0));
    transition: transform var(--t-med);
}

@media (prefers-reduced-motion: reduce) {
    .meter__bar {
        transition: none;
    }
}

/* --------------------------------------------------------------------------
   Form controls
   CFDS ships two incompatible input treatments (.support-form descendants and
   .calc-field). This standardises on the .calc-field treatment and gives it
   reusable class names.
   -------------------------------------------------------------------------- */

.field {
    display: flex;
    flex-direction: column;
    gap: var(--gap-xs);
    margin-block-end: var(--gap-md);
}

.field > label,
.field-label {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--ink-700);
}

.field input[type="text"],
.field input[type="url"],
.field input[type="password"],
.field input[type="number"],
.field select,
.field textarea,
.input,
.select {
    width: 100%;
    padding: 10px 12px;
    font: inherit;
    font-size: 0.95rem;
    color: var(--ink-900);
    background: var(--bg);
    border: 1px solid var(--ink-300);
    border-radius: var(--r-md);
    transition:
        border-color var(--t-fast),
        box-shadow var(--t-fast);
}

.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible,
.input:focus-visible,
.select:focus-visible {
    outline: none;
    border-color: var(--brand-400);
    box-shadow: var(--ring);
}

.field input[aria-invalid="true"],
.input[aria-invalid="true"] {
    border-color: var(--danger-500);
}

.field-hint {
    font-size: 0.78rem;
    color: var(--ink-500);
}

.field-error {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--danger-500);
}

.field-row {
    display: grid;
    gap: var(--gap-md);
    grid-template-columns: 1fr;
}

@media (min-width: 760px) {
    .field-row--2 {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* Checkbox rows read as one control, not a stray box and a label. */
.field-check {
    display: flex;
    align-items: flex-start;
    gap: var(--gap-sm);
    margin-block-end: var(--gap-md);
}

.field-check input[type="checkbox"] {
    inline-size: 18px;
    block-size: 18px;
    margin-block-start: 2px;
    accent-color: var(--brand-600);
    flex: none;
}

.field-check label {
    font-size: 0.92rem;
    color: var(--ink-800);
}

.field-check .field-hint {
    display: block;
    margin-block-start: 2px;
}

/* Inline toolbar selects (site / interval pickers). */
.toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--gap-sm);
}

.toolbar .select {
    width: auto;
    min-width: 150px;
}

@media (max-width: 560px) {
    .app-main {
        padding-block-start: var(--gap-md);
    }

    .toolbar {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    .toolbar > .select,
    .toolbar .range-picker,
    .toolbar .range-picker .select {
        width: 100%;
        min-width: 0;
    }

    .toolbar .filter-badges {
        grid-column: 1 / -1;
    }

    .card-head,
    .card-body {
        padding-inline: var(--gap-md);
    }
}

/* CFDS has no disabled button state. */
.btn[disabled],
.btn[aria-disabled="true"] {
    opacity: 0.55;
    cursor: not-allowed;
    transform: none;
}

.btn-danger {
    background: var(--danger-500);
    color: #fff;
    border-color: var(--danger-500);
}

.btn-danger:hover {
    filter: brightness(0.94);
}

/* --------------------------------------------------------------------------
   Status pills - reuses the roadmap-tag vocabulary, which is the only real
   status-badge set CFDS ships.
   -------------------------------------------------------------------------- */

.pill {
    display: inline-flex;
    align-items: center;
    gap: var(--gap-xs);
    padding: 3px 10px;
    border-radius: var(--r-full);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    white-space: nowrap;
    border: 1px solid transparent;
}

.pill--ok {
    background: #ecfdf5;
    color: #047857;
    border-color: #a7f3d0;
}

.pill--warn {
    background: #fef3c7;
    color: #854d0e;
    border-color: #fde68a;
}

.pill--error {
    background: #fef2f2;
    color: #991b1b;
    border-color: #fecaca;
}

.pill--muted {
    background: var(--ink-100);
    color: var(--ink-700);
    border-color: var(--ink-200);
}

.pill--brand {
    background: var(--brand-50);
    color: var(--brand-700);
    border-color: var(--brand-100);
}

/* --------------------------------------------------------------------------
   Flash messages
   -------------------------------------------------------------------------- */

.flash {
    padding: var(--gap-sm) var(--gap-md);
    border-radius: var(--r-md);
    border: 1px solid;
    font-size: 0.92rem;
    margin-block-end: var(--gap-md);
}

.flash--ok {
    background: #ecfdf5;
    color: #065f46;
    border-color: #a7f3d0;
}

.flash--error {
    background: #fef2f2;
    color: #991b1b;
    border-color: #fecaca;
}

/* --------------------------------------------------------------------------
   Empty and loading states
   -------------------------------------------------------------------------- */

.empty-state {
    padding: var(--gap-xl) var(--gap-lg);
    text-align: center;
    color: var(--ink-500);
}

.empty-state h3 {
    margin: 0 0 var(--gap-xs);
    font-family: var(--font-sans);
    font-size: 1rem;
    font-weight: 650;
    color: var(--ink-700);
}

.empty-state p {
    margin: 0 auto var(--gap-md);
    max-width: 46ch;
    font-size: 0.92rem;
}

.is-loading {
    color: var(--ink-400);
    font-size: 0.88rem;
}

/* --------------------------------------------------------------------------
   Pagination
   -------------------------------------------------------------------------- */

.pager {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--gap-sm);
    padding: var(--gap-sm) var(--gap-md);
    border-block-start: 1px solid var(--ink-100);
}

.pager__label {
    font-size: 0.82rem;
    color: var(--ink-500);
    margin-inline-end: auto;
}

/* --------------------------------------------------------------------------
   KPI tiles - CFDS .calc-result, widened for dashboard use.
   Values are sans and tabular: the serif is right for headings and wrong for
   numbers that need to be compared down a column.
   -------------------------------------------------------------------------- */

.kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--gap-md);
}

.kpi {
    padding: var(--gap-md);
    border-radius: var(--r-lg);
    background: var(--bg-alt);
    border: 1px solid var(--ink-100);
}

.kpi--primary {
    background: var(--brand-50);
    border-color: var(--brand-100);
}

.kpi__value {
    display: block;
    font-family: var(--font-sans);
    font-size: 1.7rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    font-variant-numeric: tabular-nums;
    color: var(--ink-900);
}

.kpi--primary .kpi__value {
    color: var(--brand-700);
}

.kpi__label {
    display: block;
    margin-block-start: 2px;
    font-size: 0.76rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-500);
}

.kpi__delta {
    font-size: 0.78rem;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
}

.kpi__delta--up {
    color: #047857;
}
.kpi__delta--down {
    color: var(--danger-500);
}

@media (max-width: 560px) {
    .kpis {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .kpis > .kpi:last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }
}

@media (max-width: 350px) {
    .kpis {
        grid-template-columns: 1fr;
    }

    .kpis > .kpi:last-child:nth-child(odd) {
        grid-column: auto;
    }
}

/* --------------------------------------------------------------------------
   Utilities. Kept to the few that earn their place; anything reused more than
   a couple of times should become a component instead.
   -------------------------------------------------------------------------- */

.stack-sm > * + * {
    margin-block-start: var(--gap-sm);
}
.stack-md > * + * {
    margin-block-start: var(--gap-md);
}
.stack-lg > * + * {
    margin-block-start: var(--gap-lg);
}

.muted {
    color: var(--ink-500);
}
.nowrap {
    white-space: nowrap;
}
.mono {
    font-family: var(--font-mono);
    font-size: 0.86em;
}
.truncate {
    max-width: 42ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   Range picker

   A preset select with a panel for explicit dates. The panel is positioned
   against the picker rather than the toolbar so it stays under the control
   that opened it when the toolbar wraps on narrow screens.
   --------------------------------------------------------------------------- */

.range-picker {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.range-picker__toggle {
    padding-inline: 8px;
}

.range-picker__panel {
    position: absolute;
    inset-block-start: calc(100% + 6px);
    inset-inline-start: 0;
    z-index: 30;
    min-width: 320px;
    padding: var(--gap-md);
    background: var(--bg);
    border: 1px solid var(--ink-200);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
}

.range-picker__fields {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--gap-sm);
}

.range-picker__fields label {
    display: block;
    margin-block-end: 4px;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--ink-600);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.range-picker__note {
    margin-block-start: var(--gap-sm);
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--ink-500);
}

.range-picker__error {
    margin-block-start: var(--gap-sm);
    font-size: 0.85rem;
    color: var(--danger-500);
}

.range-picker__actions {
    display: flex;
    gap: 8px;
    margin-block-start: var(--gap-md);
}

@media (max-width: 640px) {
    .range-picker__panel {
        /* Below 380px two date inputs do not fit side by side, and the native
           picker widget is wider than the column it would be given. */
        min-width: min(320px, calc(100vw - 32px));
    }

    .range-picker__fields {
        grid-template-columns: 1fr;
    }
}

/* ---------------------------------------------------------------------------
   Site tabs (real-time)

   Every site visible at once. Real-time is a glance-at-it screen, and a
   dropdown turns "which site is busy" into a click per site.
   --------------------------------------------------------------------------- */

.site-tabs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--gap-sm);
}

.site-tabs__list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.site-tab {
    padding: 7px 14px;
    font: inherit;
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--ink-600);
    background: var(--bg);
    border: 1px solid var(--ink-200);
    /* 4px, matching every other button. Never a pill. */
    border-radius: var(--r-xs);
    cursor: pointer;
    transition:
        color var(--t-fast),
        border-color var(--t-fast),
        background-color var(--t-fast);
}

.site-tab:hover {
    color: var(--ink-900);
    border-color: var(--ink-300);
}

.site-tab:focus-visible {
    outline: none;
    border-color: var(--brand-400);
    box-shadow: var(--ring);
}

.site-tab.is-active {
    color: var(--brand-700);
    background: var(--brand-50);
    border-color: var(--brand-300);
}

.site-tabs__pager {
    display: flex;
    align-items: center;
    gap: 6px;
}

.site-tabs__count {
    font-size: 0.82rem;
    color: var(--ink-500);
    font-variant-numeric: tabular-nums;
}

.site-tabs__empty {
    font-size: 0.9rem;
    color: var(--ink-500);
}
/* Account and API management */
.setting-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4, 1rem);
    padding: 0.85rem 0;
    border-bottom: 1px solid var(--border, #e2e8f0);
}

.setting-row:last-child {
    border-bottom: 0;
}

.setting-row__actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.invitation-item {
    padding-block-end: 1rem;
    border-bottom: 1px solid var(--border, #e2e8f0);
}

.invitation-item:last-of-type {
    border-bottom: 0;
}

.invitation-item .setting-row {
    border-bottom: 0;
}

.invitation-item__link {
    padding-block: 0.25rem 0.5rem;
}

.invitation-item__link .copyable-secret__field {
    min-height: 4.5rem;
}

.api-key-scope-form {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.api-key-scope-form .select {
    min-width: 10rem;
}

.api-key-create-form {
    display: grid;
    grid-template-columns: minmax(12rem, 1fr) minmax(14rem, 1fr) auto;
    gap: 0.75rem;
    align-items: end;
}

.form-inline {
    display: flex;
    gap: 0.75rem;
    align-items: end;
}

.form-inline .input {
    max-width: 24rem;
}

.settings-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    align-items: end;
}

.copyable-secret {
    display: grid;
    gap: 0.75rem;
}

.copyable-secret__field {
    display: block;
    width: 100%;
    min-height: 5.5rem;
    padding: 1rem;
    border: 1px solid var(--border, #e2e8f0);
    border-radius: var(--radius-md, 0.5rem);
    background: var(--surface-subtle, #f8fafc);
    color: var(--ink-900);
    font-family: var(
        --font-mono,
        ui-monospace,
        SFMono-Regular,
        Menlo,
        Monaco,
        Consolas,
        monospace
    );
    font-size: 0.85rem;
    line-height: 1.55;
    overflow-wrap: anywhere;
    resize: vertical;
}

.copyable-secret__field:focus {
    border-color: var(--brand-500);
    outline: 3px solid color-mix(in srgb, var(--brand-500) 20%, transparent);
    outline-offset: 1px;
}

.copyable-secret__actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.copyable-secret__status {
    min-height: 1.25rem;
    color: var(--ink-600);
    font-size: 0.82rem;
}

.one-time-credential {
    display: grid;
    gap: 1rem;
    padding: 1rem;
    border: 1px solid var(--brand-200, #bfdbfe);
    border-radius: var(--radius-md, 0.5rem);
    background: var(--brand-50, #eff6ff);
}

.one-time-credential h3,
.one-time-credential p {
    margin: 0;
}

.one-time-credential p {
    margin-block-start: 0.25rem;
    color: var(--ink-600);
}

@media (max-width: 640px) {
    .settings-grid {
        grid-template-columns: 1fr;
    }
    .form-inline {
        align-items: stretch;
        flex-direction: column;
    }
    .setting-row {
        align-items: flex-start;
        flex-direction: column;
    }
    .setting-row__actions {
        justify-content: flex-start;
    }
    .api-key-create-form {
        grid-template-columns: 1fr;
    }
    .api-key-scope-form {
        align-items: stretch;
        flex-direction: column;
        width: 100%;
    }
}
