/*
 * zcore — dashboard page
 * command-centre layout (no tabs, no outer scroll):
 *   HERO       — identity + KPI meta + rank progress, reuses .settings-hero-*
 *                language so dashboard and settings share one hero spec
 *   MAIN col   — activity snapshot (heatmap + recent)
 *   SIDE col   — my subscriptions + client download
 * the viewport-lock shell (body.is-viewport-lock) keeps the whole page inside
 * one screen; only the two body columns scroll internally when content
 * exceeds the remaining height.
 */

/* expiry-banner lives in components.css (shared with /subs). */


/* ── hero: thin overrides on top of .settings-hero ──────────────────── */

.dash-hero {
    margin-bottom: var(--sp-4);
    /* inside the viewport-lock shell every flex child except .dash-body
       must not compress — otherwise the hero squashes when the viewport
       is short and the body steals space via flex:1. */
    flex-shrink: 0;
}

/* semantic value tints inside the hero KPI row — render_kpi_meta emits
   these spans to colour "4" green, "0 c" yellow, "v1.2.1" accent etc.
   components.css only defines the base .meta-value so we provide the
   tints here (dashboard is the only page that uses them this way). */
.dash-hero .meta-value .meta-accent  { color: var(--accent); }
.dash-hero .meta-value .meta-success { color: var(--success); }
.dash-hero .meta-value .meta-warning { color: var(--warning); }
.dash-hero .meta-value .meta-danger  { color: var(--danger); }

/* anchor variant of .meta-sub — components.css defines .meta-sub as a
   plain div; when it's an <a> we want a subtle hover underline instead
   of the default link colour. */
.dash-hero a.meta-sub {
    display: block;
    width: fit-content;
    color: var(--text-dim);
    text-decoration: none;
    border-bottom: 1px dashed transparent;
    transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.dash-hero a.meta-sub:hover {
    color: var(--text);
    border-bottom-color: var(--border-strong);
}

/* badge slots next to the welcome line. :empty collapses them so flex
   gap doesn't leave orphan whitespace when role or rank hasn't loaded. */
.dash-hero-badge-slot { display: inline-flex; align-items: center; }
.dash-hero-badge-slot:empty { display: none; }

/* leaderboard position lives on the right side of the milestone footer,
   paired with the points counter on the left. */
.settings-hero-milestone-foot {
    justify-content: space-between;
}
.dash-hero-milestone-lb {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}


/* ── client download: single prominent button with version subline ──
   replaces the old multi-element card (title, version pill, notes,
   button, released-at). the panel is just a wrapper so we can hide the
   whole block when there's no build available; everything the user
   needs lives inside one button. */

.dash-client-panel { display: block; }
.dash-client-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    width: 100%;
    padding: 16px 18px;
    background: var(--accent);
    color: #000;
    border: 1px solid var(--accent);
    border-radius: var(--radius);
    text-decoration: none;
    cursor: pointer;
    transition: filter var(--dur) var(--ease),
                transform var(--dur) var(--ease);
}
.dash-client-btn:hover {
    filter: brightness(1.08);
    transform: translateY(-1px);
}
.dash-client-btn[disabled] { cursor: not-allowed; transform: none; filter: none; }
.dash-client-btn[disabled]:hover { transform: none; filter: none; }

/* Greyed-out state for unavailable bundles (admin disabled, no build
   yet, role gate). Subline carries the explanation. */
.dash-client-btn.is-unavailable {
    background: var(--bg-card);
    border-color: var(--border);
    color: var(--text-muted);
}
.dash-client-btn.is-unavailable .dash-client-btn-label { color: var(--text-muted); }
.dash-client-btn.is-unavailable .dash-client-btn-version {
    color: var(--text-dim);
    text-transform: lowercase;
    letter-spacing: var(--ls-default);
}

/* secondary variant — used for the EFI button next to the primary client
   download. quieter, accent-tinted outline against the card background
   instead of solid orange. */
.dash-client-btn.is-secondary {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: rgba(var(--accent-rgb), .35);
}
.dash-client-btn.is-secondary .dash-client-btn-version {
    color: var(--text-dim);
}
.dash-client-btn-label {
    font-family: var(--font-mono);
    font-size: var(--fs-body);
    font-weight: var(--fw-bold);
    letter-spacing: var(--ls-wide);
    text-transform: uppercase;
}
.dash-client-btn-version {
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    font-weight: var(--fw-medium);
    letter-spacing: var(--ls-tracked);
    color: rgba(0, 0, 0, 0.55);
    font-variant-numeric: tabular-nums;
}


/* ── main column: two-card grid on wide viewports ───────────────────
   so the activity snapshot sits properly and
   are visible without scrolling. at <= 1200 px the main column folds
   into a single stack; at <= 900 px the whole dash-body collapses
   (handled in components.css). */

.dash-main {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-4);
    align-content: start;
}
.dash-main > .card { margin-bottom: 0; }

@media (max-width: 1200px) {
    .dash-main { grid-template-columns: 1fr; }
}


/* ── activity snapshot — dense card that packs KPI strip + heatmap +
   last-5 injections into one tile. reuses .stats-heatmap-grid /
   .stats-heatmap-cell from components.css so the heatmap matches the
   /settings → activity spec. the KPI strip sits at the top of the card,
   the heatmap runs full-width underneath, and recent injections stack
   below with one row per inject (game · plan · version · points · when)
   so the rows actually tell you what happened instead of repeating
   "Basic · 3d ago" five times. */

/* KPI strip — icon + value pills, one per stat. labels move to the
   title attribute (hover) so nothing can truncate. pills share a flat
   dark surface and wrap cleanly when the card narrows. */
.dash-activity-kpis {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 6px;
    margin-bottom: var(--sp-3);
}
.dash-activity-kpi {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    white-space: nowrap;
    min-width: 0;
    transition: border-color var(--dur) var(--ease);
}
.dash-activity-kpi:hover { border-color: var(--border-strong); }
.dash-activity-kpi-icon {
    color: var(--text-dim);
    font-size: var(--fs-sm);
    flex-shrink: 0;
}
.dash-activity-kpi-value {
    font-family: var(--font-mono);
    font-weight: var(--fw-semi);
    font-variant-numeric: tabular-nums;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
}
.dash-activity-kpi.is-fav {
    /* fav takes all remaining width on the row so long game names
       like "Escape from Tarkov" fit without ellipsis at typical card
       widths; shrinks below 140 px only when the row can't fit it. */
    flex: 1 1 0;
    min-width: 140px;
    padding: 6px 10px 6px 8px;
}
.dash-activity-kpi.is-fav .dash-activity-kpi-icon { color: var(--accent); }
.dash-activity-kpi.is-fav .dash-activity-kpi-value {
    font-family: var(--font-main);
    font-weight: var(--fw-medium);
    color: var(--accent);
    min-width: 0;
}

/* heatmap full-width block + inline legend on the same row as the label.
   shrink the cell size from the /settings 22 px default to 14 px so the
   whole grid lives in ~ 110 px of vertical instead of 160 px — that
   gives the recent-injections list the room to show 4-5 rows without
   the card pushing past the viewport. */
.dash-activity-heatmap-wrap {
    margin-bottom: var(--sp-3);
}
.dash-activity-heatmap-wrap #dash-activity-heatmap {
    margin-bottom: 6px;
}
/* cells stretch to fill the grid column (1fr) but stay short vertically
   via a fixed height.  overrides the /settings aspect-ratio: 1/1 so the
   dashboard heatmap becomes a wide strip that actually fills the card
   — 13 cols × 1fr × N px card width ≈ one cell per ~30 px wide × 14 px
   tall on a 450 px card. */
.dash-activity-heatmap-wrap .stats-heatmap-grid {
    width: 100%;
    gap: 3px;
}
.dash-activity-heatmap-wrap .stats-heatmap-week {
    gap: 3px;
}
.dash-activity-heatmap-wrap .stats-heatmap-cell {
    width: 100%;
    height: 14px;
    aspect-ratio: auto;
    min-height: 0;
}

/* recent injections — header label + bordered rows. */
.dash-activity-recent-label {
    font-size: var(--fs-micro);
    text-transform: uppercase;
    letter-spacing: var(--ls-tracked);
    color: var(--text-dim);
    margin-bottom: 6px;
}
.dash-activity-injections {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.dash-activity-inj-row {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    transition: border-color var(--dur) var(--ease);
}
.dash-activity-inj-row:hover { border-color: var(--border-strong); }
.dash-activity-inj-main {
    min-width: 0;
    display: flex;
    align-items: baseline;
    gap: 6px;
    overflow: hidden;
}
.dash-activity-inj-game {
    font-weight: var(--fw-semi);
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.dash-activity-inj-module {
    font-family: var(--font-mono);
    color: var(--text-dim);
    white-space: nowrap;
    flex-shrink: 0;
}
.dash-activity-inj-sep {
    color: var(--border-strong);
}
.dash-activity-inj-pts {
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    color: var(--success);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.dash-activity-inj-pts.is-zero { color: var(--text-dim); }
.dash-activity-inj-when {
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    color: var(--text-dim);
    white-space: nowrap;
}

/* hero hwid cell — inline reset request link sits next to the copy
   button. low-weight visual so it doesn't compete with the value. */
.meta-hwid-reset {
    margin-left: var(--sp-2);
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    color: var(--text-dim);
    background: transparent;
    border: none;
    padding: 0;
    cursor: pointer;
    text-transform: none;
    letter-spacing: var(--ls-none);
    transition: color var(--dur) var(--ease);
}
.meta-hwid-reset:hover { color: var(--accent); }

/* recent updates feed — matches .dash-activity-inj-row density so the
   two cards in dash-main read as the same design system. */
.dash-updates-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    /* graceful overflow: many updates scroll inside the card instead
       of pushing the dash-main grid row taller. */
    max-height: 360px;
    overflow-y: auto;
}
.dash-update-item {
    display: grid;
    /* mirrors .dash-activity-inj-row: badge | content (1fr) | meta | meta */
    grid-template-columns: auto 1fr auto auto;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    transition: border-color var(--dur) var(--ease);
}
.dash-update-item:hover { border-color: var(--border-strong); }
.dash-update-game {
    font-weight: var(--fw-semi);
    font-size: var(--fs-body);
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.dash-update-version {
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    color: var(--text-dim);
    white-space: nowrap;
}
.dash-update-when {
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    color: var(--text-dim);
    white-space: nowrap;
}
