/* ==========================================================================
   Listening History — components that are genuinely specific to this app.
   ==========================================================================

   The layout primitives, cards, tables, buttons, menus, stat tiles, badges,
   forms and flashes all come from `shared/ui`
   (styles/vendor/{tokens,system}.css); the app's hue, radii and type come from
   `theme.css`. What is left here is listening history's own furniture: the top
   bar's search, the listening-behaviour visualisations, the artist lifecycle
   grid and the Chart.js palette.

   Where a rule below only adjusts density — how narrow a tile may get, how far
   apart two columns sit — it sets the shared token in `theme.css` rather than
   restating the rule it came from.

   Same rule as the shared package: reference tokens, never raw values. The
   only literals below are in the app-token block, which is where colour is
   defined rather than used.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. App tokens
   -------------------------------------------------------------------------- */
:root {
    /* Chart.js series palette. Categorical: no order is implied, and the
       first entry is the accent so a single-series chart reads as "the app's
       colour". The scripts read these off :root, so charts follow the theme
       instead of carrying their own hard-coded light and dark variants. */
    --chart-1:  light-dark(#0d9488, #2dd4bf);
    --chart-2:  light-dark(#3b82f6, #60a5fa);
    --chart-3:  light-dark(#f59e0b, #fbbf24);
    --chart-4:  light-dark(#ef4444, #f87171);
    --chart-5:  light-dark(#8b5cf6, #a78bfa);
    --chart-6:  light-dark(#ec4899, #f472b6);
    --chart-7:  light-dark(#10b981, #34d399);
    --chart-8:  light-dark(#f97316, #fb923c);
    --chart-9:  light-dark(#06b6d4, #22d3ee);
    --chart-10: light-dark(#84cc16, #a3e635);
    --chart-11: light-dark(#6366f1, #818cf8);
    --chart-12: light-dark(#14b8a6, #5eead4);
    /* Points that carry no category — the "one and done" quadrant. */
    --chart-null: var(--muted);

    /* Activity heatmap ramp: one hue, five steps of the same emerald. */
    --grid-c0: light-dark(#e6efeb, #1c2b25);
    --grid-c1: light-dark(#99e6d1, #1a4a3a);
    --grid-c2: light-dark(#34d399, #0d6b56);
    --grid-c3: light-dark(#0d9488, #14b8a6);
    --grid-c4: light-dark(#065f46, #5eead4);

    /* Artist lifecycle archetypes. Four states of one relationship to an
       artist, so they are a palette rather than a scale. */
    --lc-permanent: light-dark(#0d9488, #5eead4);
    --lc-revived:   light-dark(#f59e0b, #fcd34d);
    --lc-phase:     light-dark(#8b5cf6, #c4b5fd);
    --lc-faded:     light-dark(#64748b, #cbd5e1);
}

/* --------------------------------------------------------------------------
   2. Page frame
   -------------------------------------------------------------------------- */
body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

main.container { flex: 1; width: 100%; }

h1, h2, h3, h4, h5, h6 { font-family: var(--font-display); }

/* --------------------------------------------------------------------------
   3. Top bar: search
   -------------------------------------------------------------------------- */
/* "Listening History" is two words and must not break across lines. */
.brand { white-space: nowrap; }

.topbar-search {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.25rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--card-2);
    color: var(--muted);
}
.topbar-search:focus-within { border-color: var(--primary); }
.topbar-search input {
    width: 11rem;
    max-width: 30vw;
    border: none;
    background: none;
    font: inherit;
    font-size: 0.85rem;
    color: var(--text);
}
.topbar-search input:focus { outline: none; }

/* The open state of shared/ui's `.menu`, which ships the closed and hover
   states only. */
.menu[open] > summary { color: var(--text); background: var(--card-2); }

/* In the drawer the search is a full-width field at the top of the panel
   rather than a pill in a bar, so it drops the pill's shape constraints. The
   `order: 4` this used to carry belonged to the wrapping topbar, which the
   drawer replaced. */
@media (max-width: 720px) {
    .nav-panel .topbar-search {
        width: 100%;
        border-radius: var(--r-s);
        padding: 0.35rem 0.7rem;
        min-height: var(--tap-min);
    }
    .nav-panel .topbar-search input {
        width: 100%;
        max-width: none;
        /* 16px, to stay above the size at which iOS zooms the page on focus —
           the shared tier sets this, and the pill's 0.85rem would undo it. */
        font-size: 16px;
    }
}

/* --------------------------------------------------------------------------
   4. Page head
   -------------------------------------------------------------------------- */
/* A page head here carries a breadcrumb above the title, so the cluster aligns
   on its top edge rather than shared/ui's centre — and the icon chip sits a
   little tighter and smaller to suit the extra line. */
.page-head { align-items: flex-start; }
.page-titles { align-items: flex-start; gap: 0.75rem; }
.page-icon { width: 2.4rem; height: 2.4rem; font-size: 1.1rem; }

.breadcrumb {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin: 0 0 0.15rem;
    padding: 0;
    list-style: none;
    font-size: 0.8rem;
    color: var(--muted);
}
.breadcrumb li + li::before { content: '/'; margin-right: 0.35rem; color: var(--border-strong); }
.breadcrumb a { color: var(--muted); text-decoration: none; }
.breadcrumb a:hover { color: var(--primary); }

/* --------------------------------------------------------------------------
   5. Stat tiles
   -------------------------------------------------------------------------- */
/* The tiles come from shared/ui: `.tile` is the plain centred figure this app
   uses throughout (`.tile-lead` is the icon-beside-figure variant, unused
   here). How narrow one may get is `--tile-min` in theme.css. What is left
   here is what a tile does *inside a card*, which the package has no view on. */

/* Inside a card the tiles are already framed — drop back to a flat well. */
.card .tile { background: var(--card-2); border-color: transparent; box-shadow: none; }

/* Auto-fit would fill a card's width with seven narrow tiles and leave the
   eighth alone on a second row. Four per row divides the session figures
   evenly instead. */
@media (min-width: 860px) {
    .card .tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------------------
   6. Tables
   -------------------------------------------------------------------------- */
.grid tbody tr:hover { background: color-mix(in srgb, var(--primary) 5%, transparent); }
.grid tr.is-active { background: var(--primary-soft); }
.grid .num { text-align: right; }
.grid .rank { width: 3rem; color: var(--muted); }
.grid .name { font-weight: 600; }
.grid .sub { color: var(--muted); }
/* The face comes from shared/ui's `.mono`; a table column wants it a shade
   smaller than that helper's default. */
.grid .mono { font-size: 0.82rem; }
.grid .clip { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.grid a { text-decoration: none; }
.grid a:hover { text-decoration: underline; }
.grid .sub a { color: inherit; }

/* "Nothing to show" inside a frame that already exists. */
.empty { padding: 1.25rem; margin: 0; text-align: center; color: var(--muted); }

/* Play log: a long list scrolled inside its frame, so the head has to stay. */
.play-log thead th { position: sticky; top: 0; z-index: 1; }
.play-log .day-row td {
    padding: 0.3rem 0.75rem;
    background: var(--card-2);
    font-weight: 600;
    font-size: 0.8rem;
    color: var(--muted);
}
.play-log .outcome { width: 3rem; text-align: center; }
.play-log .ok { color: var(--pos); }
.play-log .skipped { color: var(--warn); }
.play-log .back { color: var(--muted); }

/* --------------------------------------------------------------------------
   7. Filter bars (sort order, year)
   -------------------------------------------------------------------------- */
/* The controls themselves are shared/ui's `.segmented segmented-pills` — the
   wrapping variant, because a year filter is one pill per year and there can
   be twenty of them. This is the row they sit in. */
.filters { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; margin-bottom: 1.25rem; }

/* The cross-app "seen live" button: concerts' own accent, so the link reads
   as pointing somewhere else in the fleet. */
.btn-seen { color: var(--pos); border-color: color-mix(in srgb, var(--pos) 45%, var(--border)); }
.btn-seen:hover { border-color: var(--pos); }
.btn.is-static { cursor: default; box-shadow: none; }

/* --------------------------------------------------------------------------
   8. Badges with meaning
   -------------------------------------------------------------------------- */
/* A badge takes the mono face but keeps its own size and a lighter weight —
   shared/ui's `.mono` helper carries a size of its own, so it has to be
   answered here rather than only added to. */
.badge.mono { font-size: 0.78rem; font-weight: 500; }
.badge-done       { --badge-accent: var(--pos); }
.badge-processing { --badge-accent: var(--primary); }
.badge-pending    { --badge-accent: var(--muted); }
.badge-failed     { --badge-accent: var(--neg); }

/* The search page's one-line form: field plus submit. */
.search-form { display: flex; gap: 0.5rem; align-items: stretch; margin-bottom: 1.5rem; }
.search-form input { flex: 1; }
.search-form .btn { flex: none; }

/* A plain list inside a .form-card — shared/ui styles a bare <ul> there as the
   form's error list, so this one has to out-specify it to say it is not that. */
.file-list { margin: 0.75rem 0 0; padding: 0; list-style: none; }
.file-list li { padding: 0.15rem 0; }
.form-card .file-list { color: var(--text-2); font-size: 0.85rem; }

.import-hint { margin: 0 0 1rem; color: var(--text-2); }

/* --------------------------------------------------------------------------
   9. Card headings and footers
   -------------------------------------------------------------------------- */
.card > h2 {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.card-note, .list-note { font-family: var(--font-body); font-size: 0.8rem; font-weight: 400; color: var(--muted); }

/* A heading one level below a card's own — labels a block inside it. */
.sub-title { margin: 0 0 0.5rem; font-size: 0.85rem; font-weight: 600; color: var(--text-2); }

/* shared/ui's `.card-foot` is a full-bleed band in `--card-2` that reaches the
   card's edges. Here the footer is a chart legend or a one-line note, which
   reads better as a hairline rule inside the card's own padding — so this is a
   deliberate divergence, and it has to answer every property of the shared
   rule rather than override half of it. */
.card-foot {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin: 0.9rem 0 0;
    padding: 0.75rem 0 0;
    border-top: 1px solid var(--border);
    border-radius: 0;
    background: none;
    font-size: 0.8rem;
    color: var(--muted);
}

/* A canvas needs a sized, positioned box before Chart.js can lay it out. */
.chart-box { position: relative; }

/* --------------------------------------------------------------------------
   9b. Statistics table of contents
   -------------------------------------------------------------------------- */
.stats-toc {
    position: sticky;
    top: 0;
    z-index: 10;
    display: flex;
    gap: 0.25rem;
    overflow-x: auto;
    padding: 0.5rem 0;
    margin: 0 0 0.5rem;
    background: var(--bg);
    scrollbar-width: none;
}
.stats-toc::-webkit-scrollbar { display: none; }
.stats-toc a {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.6rem;
    border-radius: var(--r-s);
    background: var(--card);
    border: 1px solid var(--border);
    font-size: 0.78rem;
    color: var(--muted);
    text-decoration: none;
    white-space: nowrap;
    transition: color 0.15s, background 0.15s;
}
.stats-toc a:hover { color: var(--primary); background: var(--primary-soft); border-color: var(--primary); }

/* --------------------------------------------------------------------------
   10. Coverage panel
   -------------------------------------------------------------------------- */
.cov-eras { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr)); gap: 0.9rem; }
.cov-era { padding: 0.2rem 0 0.2rem 0.75rem; border-left: 3px solid var(--primary); }
.cov-era .era-name { display: flex; align-items: baseline; gap: 0.5rem; font-weight: 600; }
.cov-era .era-meta { margin-top: 0.15rem; font-size: 0.82rem; color: var(--muted); }

/* --------------------------------------------------------------------------
   11. Time-of-day drift heatmap
   -------------------------------------------------------------------------- */
.drift-grid { border-collapse: separate; border-spacing: 2px; font-size: 0.75rem; }
.drift-grid th { font-weight: 500; color: var(--muted); }
.drift-year { text-align: right; padding-right: 0.5rem; white-space: nowrap; }
.drift-hour { text-align: center; width: 20px; font-variant-numeric: tabular-nums; }
.drift-cell {
    width: 20px;
    height: 20px;
    border-radius: 3px;
    /* One hue, alpha carrying the value: the colour never implies a category. */
    background: color-mix(in srgb, var(--primary) calc(6% + var(--intensity) * 94%), var(--card));
}
.drift-peak, .drift-peak-head { padding-left: 0.75rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
.drift-peak { color: var(--muted); }

/* --------------------------------------------------------------------------
   12. Artist lifecycle grid
   -------------------------------------------------------------------------- */
.lc-group { margin-bottom: 1.5rem; }
.lc-group:last-child { margin-bottom: 0; }

.lc-heading {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0 0 0.6rem;
    font-size: 0.92rem;
    font-weight: 700;
    color: var(--accent);
}
.lc-heading .lc-desc { font-family: var(--font-body); font-size: 0.8rem; font-weight: 400; color: var(--muted); }

.lc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(140px, 100%), 1fr)); gap: 0.5rem; }

.lc-card {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    color: var(--accent);
    text-decoration: none;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.lc-card:hover { background: var(--card-2); border-color: var(--border-strong); }
.lc-card-name {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.lc-sparkline { display: block; width: 100%; height: 24px; }
.lc-card-meta {
    display: flex;
    justify-content: space-between;
    font-size: 0.7rem;
    color: var(--muted);
}

/* `--accent` is shared/ui's per-item colour hook; setting it on the group
   tints the heading, the card text and the sparkline in one place. */
.lc-permanent { --accent: var(--lc-permanent); }
.lc-revived   { --accent: var(--lc-revived); }
.lc-phase     { --accent: var(--lc-phase); }
.lc-faded     { --accent: var(--lc-faded); }

/* --------------------------------------------------------------------------
   13. Chart legends
   -------------------------------------------------------------------------- */
.swatch {
    display: inline-block;
    width: 0.7rem;
    height: 0.7rem;
    margin-right: 0.3rem;
    border-radius: 50%;
    vertical-align: middle;
    background: var(--accent, var(--muted));
}
.swatch-bar { width: 1.1rem; height: 0.6rem; border-radius: 2px; }

.q-fan-favourite { --accent: var(--chart-1); }
.q-hidden-gem    { --accent: var(--chart-2); }
.q-abandoned     { --accent: var(--chart-3); }
.q-one-and-done  { --accent: var(--chart-null); }
.dr-new-artists  { --accent: var(--chart-2); }
.dr-new-share    { --accent: var(--chart-3); }

/* --------------------------------------------------------------------------
   14. Listening behaviour bars
   -------------------------------------------------------------------------- */
.meter { margin-bottom: 0.9rem; }
.meter:last-child { margin-bottom: 0; }
.meter-head {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.3rem;
    font-size: 0.83rem;
}
.meter-head .val { font-variant-numeric: tabular-nums; color: var(--text-2); }
.meter .hbar { background: var(--accent, var(--primary)); }
.meter-offline   { --accent: var(--warn); }
.meter-incognito { --accent: var(--muted); }

/* --------------------------------------------------------------------------
   15. Trips
   -------------------------------------------------------------------------- */
.trip-timeline {
    position: relative;
    height: 28px;
    border-radius: var(--r-s);
    overflow: hidden;
    background: var(--card-2);
}
.trip-band {
    position: absolute;
    top: 0;
    bottom: 0;
    opacity: 0.82;
    cursor: default;
    transition: opacity 0.15s ease;
}
.trip-band:hover { opacity: 1; }

.trip-timeline-years { position: relative; height: 18px; margin: 3px 0 1.25rem; }
.trip-timeline-years span {
    position: absolute;
    transform: translateX(-50%);
    font-size: 0.68rem;
    color: var(--muted);
    white-space: nowrap;
}

.trip-flag { font-size: 1.2rem; line-height: 1; }
.trip-countries { display: inline-flex; gap: 3px; }
.trip-cc {
    padding: 0 4px;
    border: 1px solid var(--border);
    border-radius: 3px;
    background: var(--card-2);
    font-size: 0.65rem;
    color: var(--muted);
}

/* The body of a shared/ui `.group` accordion, continuing its frame. */
.group-body {
    padding: 0.75rem 0.95rem;
    background: var(--card);
    border: 1px solid var(--border);
    border-top: none;
    border-radius: 0 0 var(--r-m) var(--r-m);
}

/* --------------------------------------------------------------------------
   16. Activity heatmap
   -------------------------------------------------------------------------- */
.activity-grid { display: flex; gap: 2px; align-items: flex-start; }
.activity-grid .week { display: flex; flex-direction: column; gap: 2px; }
.activity-cell, .activity-key i { width: 12px; height: 12px; border-radius: 2px; }

.activity-key {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 0.6rem;
    font-size: 0.8rem;
    color: var(--muted);
}
.activity-key .ramp { display: inline-flex; gap: 2px; }
.activity-key i { display: inline-block; }
