/*
    AuScope tracker pages — shared stylesheet
    Common skin for earthbank.html and auspass.html.
    Page-specific rules (table columns, panes, badge variants,
    fleet-grid column count, table-layout) live in each page's <style>.
*/

:root {
    --bg: #ffffff;
    --bg-soft: #f8fafc;
    --bg-muted: #f1f5f9;
    --border: #e5e7eb;
    --border-strong: #cbd5e1;
    --text: #0f172a;
    --text-soft: #475569;
    /* Was #94a3b8, which scored 2.34:1 on --bg-muted and 2.56:1 on white —
       a WCAG AA failure everywhere it carried text, and it carried a lot:
       stat labels, zero citation pills, "no record" rows, fleet zero counts.
       #5e6a7a clears 4.5:1 on white, --bg-soft and --bg-muted alike. Use
       --text-faint for genuinely decorative marks that carry no meaning. */
    --text-muted: #5e6a7a;
    --text-faint: #94a3b8;
    --accent: #2563eb;
    --accent-strong: #1d4ed8;
    --accent-soft: #dbeafe;
    --accent-bg: #eff6ff;
    --good: #16a34a;
    --good-bg: #dcfce7;
    /* Was #ca8a04 — 2.94:1 on white, under even the 3:1 floor for a
       non-text indicator. #a16207 clears 4.9:1. */
    --warn: #a16207;
    --warn-bg: #fef3c7;
    --bad: #dc2626;
    --bad-bg: #fee2e2;
    --active: #059669;
    --active-bg: #d1fae5;
    /* Text-safe partners for the status hues above: --good and --active are
       fine as dots and borders but fail AA as small text on white. */
    --good-text: #15803d;
    --warn-text: #92400e;
    --bad-text: #b91c1c;
    --focus-ring: #1d4ed8;
    --mono: 'SFMono-Regular', 'Menlo', 'Cascadia Mono', 'Consolas', monospace;
    --sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Tahoma, Geneva, sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
    font-family: var(--sans);
    background: var(--bg);
    color: var(--text);
    font-size: 14px;
    line-height: 1.5;
}

.wrap {
    max-width: 1400px;
    margin: 0 auto;
    padding: 24px 28px 80px;
}

/* ========== HEADER ========== */
.topbar {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    /* No border here: the site-tabs rule below the topbar is the ONE divider
       every page shares. A second line under the brand made chassis pages
       carry two rules while the hub carried one. */
    padding-bottom: 12px;
    flex-wrap: wrap;
    gap: 12px;
}

/* Header-only wrapper for pages whose content is NOT inside .wrap (the hub's
   full-bleed hero): same geometry as .wrap, no bottom padding. */
.site-head {
    max-width: 1400px;
    margin: 0 auto;
    padding: 24px 28px 0;
}
.brand h1 {
    font-size: 22px;
    font-weight: 600;
    color: var(--text);
    letter-spacing: -0.01em;
}
.brand h1 .accent {
    /* Pinned to AuScope purple, NOT var(--accent): pages re-theme their
       accent (blue trackers, purple pillars) and the header must not change
       colour as you tab between them. The header belongs to the site, not
       the page. */
    color: #282572;
    font-weight: 700;
}
.brand p {
    font-size: 13px;
    color: var(--text-soft);
    margin-top: 4px;
}
.topbar .links {
    display: flex;
    gap: 16px;
    font-size: 13px;
}
.topbar .links a {
    color: var(--accent);
    text-decoration: none;
}
.topbar .links a:hover { text-decoration: underline; }

.auscope-logo {
    height: 28px;
    width: auto;
    vertical-align: -8px;
    margin-right: 10px;
}
/* Text fallbacks shown when image assets fail to load */
.auscope-fallback {
    color: var(--accent);
    font-weight: 700;
    font-size: 18px;
    margin-right: 10px;
    letter-spacing: -0.01em;
}

/* ========== STAT TILES ========== */
.stats {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 10px;
    margin-bottom: 20px;
}
@media (max-width: 900px) {
    .stats { grid-template-columns: repeat(2, 1fr); }
}
.stat {
    border: 1px solid var(--border);
    background: var(--bg-soft);
    border-radius: 6px;
    padding: 12px 14px;
}
.stat .label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 600;
}
.stat .value {
    font-size: 22px;
    font-weight: 600;
    color: var(--text);
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
}
.stat .sub {
    font-size: 11px;
    color: var(--text-soft);
    margin-top: 2px;
}

/* ========== CONTROL BAR ========== */
.controls {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-bottom: 14px;
    flex-wrap: wrap;
}
.controls input[type="search"],
.controls select {
    font-family: var(--sans);
    font-size: 13px;
    padding: 7px 10px;
    border: 1px solid var(--border);
    border-radius: 5px;
    background: var(--bg);
    color: var(--text);
    outline: none;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.controls input[type="search"] { min-width: 280px; }
.controls input[type="search"]:focus,
.controls select:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}
.controls .btn {
    font-family: var(--sans);
    font-size: 13px;
    padding: 7px 12px;
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text);
    border-radius: 5px;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}
.controls .btn:hover { background: var(--bg-muted); }
.controls .btn.primary {
    border-color: var(--accent);
    color: var(--accent);
}
.controls .btn.primary:hover { background: var(--accent-bg); }
.controls .btn.toggled {
    background: var(--accent);
    color: white;
    border-color: var(--accent);
}
.controls .spacer { flex: 1; }
.controls .meta {
    font-size: 12px;
    color: var(--text-soft);
}

/* ========== TABLE ========== */
.table-wrap {
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
}
table.data {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}
table.data thead th {
    background: var(--bg-muted);
    color: var(--text);
    text-align: left;
    font-weight: 600;
    padding: 9px 12px;
    border-bottom: 1px solid var(--border-strong);
    white-space: nowrap;
    font-size: 12px;
    user-select: none;
}
table.data thead th.sortable { cursor: pointer; }
table.data thead th.sortable:hover { color: var(--accent); }
table.data thead th .arrow {
    display: inline-block;
    margin-left: 4px;
    color: var(--text-muted);
    font-size: 10px;
}
table.data thead th.sorted .arrow { color: var(--accent); }
table.data tbody td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
    vertical-align: top;
}
table.data tbody tr.data-row { cursor: pointer; transition: background 0.08s; }
table.data tbody tr.data-row:hover { background: var(--accent-bg); }
table.data tbody tr.data-row.expanded { background: var(--accent-bg); }
table.data tbody tr.data-row.expanded td { border-bottom: 1px solid var(--accent-soft); }

.col-num { width: 40px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.col-actions { width: 50px; text-align: right; }

table.data .doi {
    font-family: var(--mono);
    font-size: 11px;
    color: var(--text-soft);
    margin-top: 2px;
    display: inline-block;
    text-decoration: none;
}
table.data .doi:hover { color: var(--accent); }

/* badges */
.badge {
    display: inline-flex;
    align-items: center;
    font-size: 11px;
    padding: 2px 8px;
    border-radius: 10px;
    font-weight: 500;
    white-space: nowrap;
}

.cite-pill {
    display: inline-block;
    min-width: 32px;
    padding: 2px 8px;
    border-radius: 10px;
    background: var(--accent-soft);
    color: var(--accent-strong);
    font-weight: 600;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
}
.cite-pill.zero { background: var(--bg-muted); color: var(--text-muted); }
.cite-pill.loading {
    background: transparent;
    color: var(--text-muted);
    font-weight: 400;
}
.cite-pill .gap-marker {
    display: inline-block;
    margin-left: 4px;
    font-size: 10px;
    color: #b45309;
}

.actions-btn {
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 4px 6px;
    font-size: 14px;
    color: var(--text-muted);
    border-radius: 3px;
    transition: color 0.1s, background 0.1s;
}
.actions-btn:hover { color: var(--accent); background: var(--accent-bg); }
.actions-btn .chevron {
    display: inline-block;
    transition: transform 0.18s;
}
tr.expanded .actions-btn .chevron { transform: rotate(180deg); }

/* ========== DETAIL PANEL ========== */
tr.detail-row td { padding: 0; background: var(--bg-soft); }
tr.detail-row .detail {
    padding: 18px 22px 22px;
    border-left: 3px solid var(--accent);
    background: var(--bg-soft);
    overflow: hidden;
    max-width: 100%;
}
.detail-tabs {
    display: flex;
    gap: 2px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 16px;
}
.detail-tab {
    padding: 8px 14px;
    font-size: 13px;
    border: none;
    background: transparent;
    color: var(--text-soft);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    font-family: var(--sans);
}
.detail-tab:hover { color: var(--text); }
.detail-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
    font-weight: 600;
}
.detail-tab .badge-count {
    display: inline-block;
    margin-left: 6px;
    background: var(--bg-muted);
    color: var(--text-soft);
    padding: 0 6px;
    border-radius: 8px;
    font-size: 11px;
    font-weight: 500;
}
.detail-tab.active .badge-count {
    background: var(--accent-soft);
    color: var(--accent-strong);
}

.detail-pane { display: none; }
.detail-pane.active { display: block; }

/* ----- Overview pane ----- */
.ov-grid {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: 4px 16px;
    font-size: 13px;
}
.ov-grid dt {
    color: var(--text-muted);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
    padding-top: 6px;
}
.ov-grid dd {
    color: var(--text);
    padding: 4px 0;
    line-height: 1.55;
}
.ov-grid dd a { color: var(--accent); text-decoration: none; }
.ov-grid dd a:hover { text-decoration: underline; }
.ov-grid dd .empty {
    display: inline-block;
    padding: 1px 7px;
    font-size: 11px;
    font-weight: 500;
    background: #fef3c7;
    color: #92400e;
    border-radius: 3px;
}
.ov-grid dd .mono { font-family: var(--mono); font-size: 12px; }

.creator {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-right: 10px;
    margin-bottom: 4px;
    padding: 2px 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 12px;
    font-size: 12px;
}
.orcid-icon {
    width: 14px;
    height: 14px;
    vertical-align: -3px;
    display: inline-block;
}
.orcid-link {
    display: inline-flex;
    align-items: center;
    text-decoration: none !important;
    line-height: 1;
    padding: 0 2px;
}
.orcid-link:hover { opacity: 0.75; }
.orcid-fallback {
    display: inline-flex;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: white;
    color: #a6ce39;
    border: 1.5px solid #a6ce39;
    align-items: center;
    justify-content: center;
    font-size: 9px;
    font-weight: 700;
    font-family: var(--mono);
    vertical-align: -3px;
    line-height: 1;
}
.ror-icon {
    width: 22px;
    height: 14px;
    vertical-align: -3px;
    object-fit: contain;
}
.ror-link {
    display: inline-flex;
    align-items: center;
    text-decoration: none !important;
    line-height: 1;
    padding: 0 2px;
}
.ror-link:hover { opacity: 0.75; }
/* text-decoration:none is load-bearing — the fallback renders inside an anchor on earthbank */
.ror-fallback {
    display: inline-flex;
    padding: 0 5px;
    border-radius: 3px;
    background: #6366f1;
    color: white;
    font-size: 9px;
    font-weight: 700;
    font-family: var(--mono);
    line-height: 14px;
    vertical-align: 1px;
    text-decoration: none;
}
.contrib-type {
    display: inline-block;
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 9px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: var(--bg-muted);
    color: var(--text-soft);
    margin-left: 4px;
    font-family: var(--mono);
    line-height: 14px;
    vertical-align: 1px;
}
.contrib-type.contact { background: #fef3c7; color: #92400e; }
.contrib-type.host { background: #dbeafe; color: #1e40af; }
.contrib-type.sponsor { background: #dcfce7; color: #166534; }

.extent-chip {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    padding: 3px 10px;
    background: var(--accent-bg);
    border: 1px solid var(--accent-soft);
    border-radius: 4px;
    margin: 2px 6px 2px 0;
}
.extent-chip .num {
    font-weight: 700;
    font-size: 14px;
    color: var(--accent-strong);
    font-variant-numeric: tabular-nums;
}
.extent-chip .unit {
    font-size: 11px;
    color: var(--text-soft);
}
.extent-chip.plain {
    background: var(--bg-soft);
    border-color: var(--border);
}
.extent-chip.plain .num { color: var(--text); }
.format-chip {
    display: inline-block;
    font-size: 11px;
    padding: 2px 8px;
    background: var(--bg-muted);
    border-radius: 4px;
    margin: 2px 4px 2px 0;
    color: var(--text-soft);
    font-family: var(--mono);
}

/* ----- Citations pane ----- */
.cit-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
    flex-wrap: wrap;
    gap: 8px;
}
.source-summary {
    display: flex;
    gap: 10px;
    font-size: 12px;
    color: var(--text-soft);
}
.source-summary .src {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 10px;
    background: var(--bg);
    border: 1px solid var(--border);
}
.source-summary .src .dot {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--text-muted);
}
.source-summary .src.has-data .dot { background: var(--good); }
.source-summary .src.error .dot { background: var(--bad); }

.citation-list {
    list-style: none;
}
.citation-item {
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: 12px;
    align-items: start;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 10px 14px;
    margin-bottom: 6px;
}
.citation-item.is-gap-novel { border-left: 3px solid var(--warn); padding-left: 11px; }
.citation-item.is-gap-known { border-left: 3px solid var(--border-strong); padding-left: 11px; }
.citation-item.is-declared-only { background: var(--bg-soft); }
.citation-item .cit-status { padding-top: 1px; }
.citation-item .cit-body { min-width: 0; }
.citation-item .title {
    font-weight: 500;
    color: var(--text);
    font-size: 13px;
    margin-bottom: 3px;
}
.citation-item .meta {
    font-size: 12px;
    color: var(--text-soft);
    line-height: 1.5;
}
.citation-item .meta a { color: var(--accent); text-decoration: none; font-family: var(--mono); font-size: 11px; }
.citation-item .meta a:hover { text-decoration: underline; }
.source-tag {
    display: inline-block;
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.tag-datacite { background: #dbeafe; color: #1e40af; }
.tag-opencitations { background: #fce7f3; color: #9d174d; }
.tag-openalex { background: #d1fae5; color: #065f46; }

/* ----- Citation reciprocity ----- */
.recip-banner {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 11px 14px;
    border-radius: 5px;
    margin-bottom: 12px;
    flex-wrap: wrap;
    gap: 10px;
    border: 1px solid;
}
.recip-banner.good { background: var(--good-bg); border-color: #86efac; }
.recip-banner.warn { background: var(--warn-bg); border-color: #fcd34d; }
.recip-banner.neutral { background: var(--bg-soft); border-color: var(--border); }
.recip-banner .recip-headline {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 6px;
    display: block;
}
.recip-pills {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    align-items: center;
}
.recip-pill {
    display: inline-flex;
    align-items: baseline;
    padding: 3px 10px;
    background: white;
    border: 1px solid var(--border);
    border-radius: 12px;
    font-size: 12px;
    color: var(--text);
    white-space: nowrap;
}
.recip-pill strong {
    margin-right: 4px;
    font-variant-numeric: tabular-nums;
}
.recip-pill.gap { border-color: #f59e0b; color: #92400e; background: #fffbeb; }
.recip-pill.gap-known { border-color: var(--border-strong); color: var(--text-soft); background: var(--bg-soft); }
.recip-pill.info { border-color: var(--border-strong); color: var(--text-soft); }

.copy-gaps-btn {
    padding: 6px 12px;
    border-radius: 4px;
    font-size: 12px;
    cursor: pointer;
    border: 1px solid #f59e0b;
    background: white;
    color: #92400e;
    font-family: var(--sans);
    font-weight: 500;
    white-space: nowrap;
}
.copy-gaps-btn:hover { background: #fffbeb; }

.recip-badge {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 3px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
}
.recip-badge.declared { background: var(--good-bg); color: #166534; }
.recip-badge.gap { background: #fef3c7; color: #92400e; }
.recip-badge.gap-known { background: var(--bg-muted); color: #475569; border: 1px solid var(--border-strong); padding: 0 6px; }
.recip-badge.declared-only { background: var(--bg-muted); color: var(--text-soft); }
.recip-badge.no-doi { background: var(--bg-muted); color: var(--text-muted); }
.recip-badge .relation {
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    font-size: 10px;
    color: inherit;
    opacity: 0.85;
    margin-left: 2px;
}

/* Gap counter on the Citations tab label.
   Keep the explicit .active variant — without it the amber counter
   only survives on the active tab by source order at tied specificity. */
.detail-tab .badge-count.gap-count {
    background: #fef3c7;
    color: #92400e;
    margin-left: 4px;
}
.detail-tab.active .badge-count.gap-count {
    background: #fef3c7;
    color: #92400e;
}

/* ----- Raw JSON ----- */
.raw-json {
    background: #0f172a;
    color: #e2e8f0;
    padding: 14px 16px;
    border-radius: 5px;
    font-family: var(--mono);
    font-size: 11.5px;
    line-height: 1.55;
    max-height: 480px;
    overflow: auto;
    white-space: pre;
}
.raw-json .key { color: #93c5fd; }
.raw-json .str { color: #86efac; }
.raw-json .num { color: #fbbf24; }
.raw-json .bool { color: #f472b6; }
.raw-json .null { color: #94a3b8; font-style: italic; }

/* ========== UTILITY ========== */
.spinner {
    display: inline-block;
    width: 12px; height: 12px;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
    vertical-align: middle;
}
@keyframes spin { to { transform: rotate(360deg); } }

.empty-state {
    padding: 40px 20px;
    text-align: center;
    color: var(--text-muted);
    font-size: 13px;
}

.toast {
    position: fixed;
    bottom: 24px; left: 50%;
    transform: translateX(-50%) translateY(20px);
    padding: 9px 16px;
    background: var(--text);
    color: white;
    border-radius: 6px;
    font-size: 13px;
    opacity: 0;
    transition: opacity 0.2s, transform 0.2s;
    pointer-events: none;
    z-index: 100;
}
.toast.show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* ========== HOVER TOOLTIPS ========== */
/* Any element with `data-tip="..."` gets a styled hover tooltip.
   Use the .info-i element for a small "(i)" badge that explains
   a nearby field. Use data-tip directly on badges/pills to enrich
   their hover affordance. */
[data-tip] {
    position: relative;
}
[data-tip]::after {
    content: attr(data-tip);
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    background: #0f172a;
    color: #f1f5f9;
    padding: 8px 11px;
    border-radius: 5px;
    font-size: 12px;
    font-weight: 400;
    font-style: normal;
    font-family: var(--sans);
    line-height: 1.45;
    letter-spacing: 0;
    text-transform: none;
    white-space: normal;
    width: max-content;
    max-width: 280px;
    text-align: left;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s 0.1s;
    z-index: 100;
    box-shadow: 0 4px 14px rgba(15, 23, 42, 0.18);
}
[data-tip]::before {
    content: '';
    position: absolute;
    top: calc(100% + 2px);
    left: 1px;
    border: 6px solid transparent;
    border-bottom-color: #0f172a;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s 0.1s;
    z-index: 100;
}
[data-tip]:hover::after,
[data-tip]:hover::before { opacity: 1; }

.info-i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--bg-muted);
    color: var(--text-soft);
    font-size: 10px;
    font-weight: 700;
    font-family: Georgia, 'Times New Roman', serif;
    font-style: italic;
    cursor: help;
    margin-left: 5px;
    vertical-align: 1px;
    user-select: none;
    line-height: 1;
    border: 1px solid transparent;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.info-i:hover {
    background: var(--accent-soft);
    color: var(--accent-strong);
    border-color: var(--accent);
}

/* ========== FLEET SUMMARY PANEL ========== */
.fleet-panel {
    border: 1px solid var(--border);
    background: var(--bg-soft);
    border-radius: 6px;
    margin-bottom: 14px;
}
.fleet-panel > summary {
    list-style: none;
    cursor: pointer;
    padding: 10px 14px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 8px;
    user-select: none;
}
.fleet-panel > summary::-webkit-details-marker { display: none; }
.fleet-panel > summary::after {
    content: '▾';
    margin-left: auto;
    color: var(--text-muted);
    transition: transform 0.15s;
    font-size: 11px;
}
.fleet-panel[open] > summary::after { transform: rotate(180deg); }
.fleet-panel .fleet-context {
    font-weight: 400;
    color: var(--text-soft);
    font-size: 12px;
}
/* grid-template-columns is set per page (earthbank 3, auspass 2) */
.fleet-grid {
    display: grid;
    gap: 10px;
    padding: 0 14px 14px;
}
@media (max-width: 900px) {
    .fleet-grid { grid-template-columns: 1fr; }
}
.fleet-section {
    background: white;
    border: 1px solid var(--border);
    border-radius: 5px;
    padding: 10px 12px;
}
.fleet-section h4 {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin-bottom: 6px;
    font-weight: 600;
}
.fleet-item {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 4px 6px;
    margin: 0 -6px;
    border-radius: 3px;
    cursor: pointer;
    font-size: 12.5px;
    transition: background 0.1s;
}
.fleet-item:hover { background: var(--accent-bg); }
.fleet-item.active { background: var(--accent-soft); color: var(--accent-strong); font-weight: 500; }
.fleet-item.zero { color: var(--text-muted); cursor: default; }
.fleet-item.zero:hover { background: transparent; }
.fleet-item .count {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    min-width: 30px;
    text-align: right;
    color: var(--text);
}
.fleet-item.zero .count { color: var(--text-muted); font-weight: 400; }
.fleet-item.active .count { color: var(--accent-strong); }
.fleet-item .label { flex: 1; line-height: 1.4; }

.fleet-filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 4px 2px 10px;
    background: var(--accent-soft);
    color: var(--accent-strong);
    border-radius: 12px;
    font-size: 12px;
    font-weight: 500;
    margin-left: 8px;
}
.fleet-filter-chip button {
    background: transparent;
    border: none;
    color: var(--accent-strong);
    cursor: pointer;
    padding: 0 5px;
    font-size: 14px;
    line-height: 1;
    border-radius: 50%;
}
.fleet-filter-chip button:hover { background: rgba(37, 99, 235, 0.15); }

/* ============================================================
   SITE TABS — the one navigation bar shared by every page family
   (Impact / Publications / Datasets, with FAIR / Projects /
   Software to join as those pages land). Injected by
   tracker-chassis.js on pages whose <body> carries data-site-tab;
   index.html and datasets.html embed the same markup statically.
   The display-artefact pages (widget, the two _map embeds) carry
   no attribute and never get a bar.
   ============================================================ */
.site-tabs {
    display: flex;
    gap: 2px;
    border-bottom: 2px solid var(--border);
    margin: 0 0 20px;
    flex-wrap: wrap;
}
.site-tabs a {
    padding: 8px 16px 7px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-soft);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    white-space: nowrap;
}
.site-tabs a:hover { color: #282572; }
.site-tabs a.active {
    /* Pinned purple for the same reason as .brand .accent above. */
    color: #282572;
    border-bottom-color: #282572;
}

/* ============================================================
   ============================================================
   HONEST-NUMBER SKIN
   The visual half of the machinery in tracker-chassis.js: source
   banners, unavailable figures, graded stat tiles, progress and
   skeletons, the glossary affordance, and the accessibility fixes
   that belong to the skin rather than to any one page.
   ============================================================
   ============================================================ */


/* ========== ACCESSIBILITY PRIMITIVES ========== */

/* Visible focus, everywhere, at 3px so it survives against the tinted
   backgrounds these pages use. Specificity is deliberate: .controls
   sets `outline: none` on its inputs at (0,2,1), so the override for
   those has to bite harder than that. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
    border-radius: 3px;
}
.controls input[type="search"]:focus-visible,
.controls select:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 1px;
}
/* Rows and fleet items are hover-tinted; the ring alone can get lost in
   the tint, so pull the tint off while focused. */
table.data tbody tr.data-row:focus-visible,
.fleet-item:focus-visible { background: var(--bg); }

.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.skip-link {
    position: absolute;
    left: 8px;
    top: -60px;
    z-index: 200;
    padding: 10px 16px;
    background: var(--text);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    border-radius: 0 0 6px 6px;
    text-decoration: none;
    transition: top 0.15s;
}
.skip-link:focus { top: 0; }

/* A sortable header is a real button now (tracker-chassis.js moves the
   th's contents inside one). It must look exactly like the plain <th>
   text it replaced — the point is keyboard operability, not a new
   visual affordance. */
button.th-sort {
    display: block;
    width: 100%;
    padding: 0;
    margin: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-align: inherit;
    white-space: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    cursor: pointer;
}
button.th-sort:focus-visible { outline-offset: 1px; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    .spinner { animation-duration: 2.4s; }
    .tp-bar.indeterminate .tp-fill,
    .skel-bar { animation: none; }
}


/* ========== GLOSSARY AFFORDANCE ========== */

/* .info-i is now a <button>. The base rule higher up this file styles
   it; these lines strip the user-agent button chrome so it lands in the
   same pixels as the old <span>. */
button.info-i {
    padding: 0;
    appearance: none;
    -webkit-appearance: none;
    font-family: Georgia, 'Times New Roman', serif;
    font-style: italic;
    line-height: 1;
}
button.info-i:hover,
button.info-i.tip-open {
    background: var(--accent-soft);
    color: var(--accent-strong);
    border-color: var(--accent);
}

.term-wrap { display: inline; position: relative; }

/* The jargon word itself, marked as glossed. Dotted underline plus the
   dashed-help cursor: never colour alone. */
button.term {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    cursor: help;
    text-decoration: underline;
    text-decoration-style: dotted;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
    text-decoration-color: var(--text-muted);
}
button.term:hover,
button.term.tip-open { text-decoration-color: var(--accent); color: var(--accent-strong); }

/* Tooltips were :hover-only, which made every gloss on this site
   invisible to keyboard and screen-reader users. Three triggers now:
   hover, keyboard focus, and a pinned click for touch. */
[data-tip]:focus-visible::after,
[data-tip]:focus-visible::before,
[data-tip].tip-open::after,
[data-tip].tip-open::before { opacity: 1; }

/* Flip to the left edge when the default left-anchored balloon would
   run off a narrow screen (tracker-chassis.js adds .tip-left). */
[data-tip].tip-left::after { left: auto; right: 0; }
[data-tip].tip-left::before { left: auto; right: 1px; }

[data-tip]::after { max-width: min(280px, calc(100vw - 32px)); }
@media (max-width: 560px) {
    [data-tip]::after { width: max-content; max-width: calc(100vw - 28px); }
}

/* The hidden balloon is still laid out (opacity:0), so a wide tip anchored
   near the right edge widens the DOCUMENT without any element overflowing —
   an 8px phantom horizontal scroll at 375px that element scans cannot find.
   Collapsing the balloon while hidden broke it when shown, so instead clip
   the phantom at the page container on small screens. Tooltips that would
   run off the right edge are already flipped by .tip-left, so nothing that
   should be visible is lost. */
@media (max-width: 700px) {
    html, body { overflow-x: clip; }
}

/* REGRESSION GUARD. Several pages span a stat tile's tooltip across the whole
   tile (`.stats .stat [data-tip] { position: static }` + left/right insets)
   so a wide gloss cannot overflow a narrow column. The glossary's new
   `.term-wrap` is position:relative and only ~19px wide, so it became the
   containing block instead of the tile and collapsed those tooltips to zero
   width — an unreadable vertical strip of single characters at 375px.
   Inside a stat tile the wrapper must not establish a containing block. */
.stats .stat .term-wrap { position: static; }
}

.gloss-list {
    display: grid;
    gap: 0;
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
}
.gloss-item {
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: 0 18px;
    padding: 11px 16px;
    border-bottom: 1px solid var(--border);
    background: var(--bg);
}
.gloss-item:last-child { border-bottom: 0; }
.gloss-item:nth-child(odd) { background: var(--bg-soft); }
.gloss-item dt { font-weight: 600; color: var(--text); font-size: 13px; }
.gloss-item dd { color: var(--text-soft); font-size: 13px; line-height: 1.55; }
.gloss-item dd strong { color: var(--text); font-weight: 600; }
.gloss-item dd a { color: var(--accent); }
@media (max-width: 700px) {
    .gloss-item { grid-template-columns: 1fr; gap: 3px; }
}


/* ========== SOURCE BANNER ==========
   Level is carried three ways at once — colour, glyph and word — so it
   survives greyscale printing, colour blindness and a screen reader.
   An outage must be impossible to mistake for a quiet page. */

.src-banner-host { display: block; }
.src-banner {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    padding: 12px 14px;
    border: 1px solid;
    border-left-width: 4px;
    border-radius: 6px;
    margin-bottom: 14px;
    font-size: 13px;
}
.src-banner-glyph {
    flex: none;
    width: 20px; height: 20px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
    margin-top: 1px;
}
.src-banner-body { flex: 1; min-width: 0; }
.src-banner-head {
    display: block;
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
}
.src-banner-word { text-transform: uppercase; letter-spacing: 0.05em; font-size: 11px; }
.src-banner-detail {
    display: block;
    margin-top: 3px;
    color: var(--text-soft);
    line-height: 1.5;
}
.src-banner-list {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 9px;
}
.src-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 9px;
    border-radius: 11px;
    background: var(--bg);
    border: 1px solid var(--border-strong);
    font-size: 11.5px;
    color: var(--text-soft);
}
.src-chip-glyph { font-weight: 700; line-height: 1; }
.src-chip-note { color: var(--text-muted); font-size: 11px; }
.src-chip.s-ok { border-color: #86efac; color: var(--good-text); }
.src-chip.s-failed { border-color: #fca5a5; color: var(--bad-text); background: var(--bad-bg); }
.src-chip.s-partial { border-color: #fcd34d; color: var(--warn-text); background: var(--warn-bg); }
.src-chip.s-loading, .src-chip.s-pending { border-style: dashed; }
.src-chip.s-skipped { opacity: 0.7; }

.src-banner.level-ok { background: var(--good-bg); border-color: #86efac; }
.src-banner.level-ok .src-banner-glyph { background: var(--good-text); color: #fff; }
.src-banner.level-loading { background: var(--bg-soft); border-color: var(--border-strong); }
.src-banner.level-loading .src-banner-glyph { background: var(--text-soft); color: #fff; }
.src-banner.level-degraded { background: var(--warn-bg); border-color: #fcd34d; }
.src-banner.level-degraded .src-banner-glyph { background: var(--warn-text); color: #fff; }
.src-banner.level-failed { background: var(--bad-bg); border-color: #fca5a5; }
.src-banner.level-failed .src-banner-glyph { background: var(--bad-text); color: #fff; }

.src-banner-retry {
    flex: none;
    align-self: center;
    padding: 6px 13px;
    border-radius: 5px;
    border: 1px solid var(--border-strong);
    background: var(--bg);
    color: var(--text);
    font-family: var(--sans);
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
}
.src-banner-retry:hover { background: var(--bg-muted); }


/* ========== FIGURES THAT REFUSE TO LIE ==========
   A source that did not answer renders an em dash and a reason. It
   never renders 0, and it never renders blank — a blank looks like a
   slow load, and a 0 looks like a fact. */

.fig-value { font-variant-numeric: tabular-nums; }

.fig-unavailable {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--text-muted);
    font-weight: 500;
    cursor: help;
    border-bottom: 1px dashed var(--border-strong);
}
.fig-unavailable::before {
    content: '⚠';
    font-size: 0.75em;
    color: var(--warn-text);
    line-height: 1;
}
.fig-unavailable:hover { color: var(--warn-text); border-bottom-color: var(--warn-text); }

.fig-partial {
    display: inline-flex;
    align-items: baseline;
    color: inherit;
    cursor: help;
    font-variant-numeric: tabular-nums;
    border-bottom: 1px dashed var(--warn);
}
.fig-partial-mark {
    font-size: 0.6em;
    vertical-align: super;
    color: var(--warn-text);
    margin-left: 1px;
    font-weight: 700;
}

/* An uncited record and an unfetched one must not be the same pixels.
   .zero is a real, confirmed zero; .unknown is "we do not know yet". */
.cite-pill.zero {
    background: transparent;
    color: var(--text-muted);
    border: 1px dashed var(--border-strong);
}
.cite-pill.unknown {
    background: transparent;
    color: var(--warn-text);
    border: 1px dashed var(--warn);
    font-weight: 500;
    cursor: help;
}


/* ========== GRADED STAT TILE ========== */

.stat.honest { display: flex; flex-direction: column; gap: 2px; }
.stat.honest .value { line-height: 1.15; }
.stat.honest .value a.stat-link {
    color: var(--text);
    text-decoration: none;
    border-bottom: 2px solid var(--accent-soft);
}
.stat.honest .value a.stat-link:hover {
    color: var(--accent-strong);
    border-bottom-color: var(--accent);
}
.stat.honest.grade-unavailable { background: var(--bad-bg); border-color: #fca5a5; }
.stat.honest.grade-unavailable .value { font-size: 18px; }
.stat.honest.grade-partial { background: var(--warn-bg); border-color: #fcd34d; }

.grade-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 5px;
    margin-top: 4px;
    font-size: 11px;
}
.grade-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 1px 7px 1px 5px;
    border-radius: 9px;
    border: 1px solid var(--border-strong);
    background: var(--bg);
    color: var(--text-soft);
    font-family: var(--sans);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    cursor: help;
}
.grade-glyph { font-size: 9px; line-height: 1; }
.grade-chip.g-measured { border-color: #86efac; color: var(--good-text); background: var(--good-bg); }
.grade-chip.g-snapshot { border-color: var(--border-strong); color: var(--text-soft); }
.grade-chip.g-partial { border-color: #fcd34d; color: var(--warn-text); background: var(--warn-bg); }
.grade-chip.g-estimate { border-color: var(--border-strong); color: var(--text-soft); background: var(--bg-muted); }
.grade-chip.g-unverified { border-color: var(--border-strong); color: var(--text-soft); background: var(--bg-muted); }
.grade-chip.g-unavailable { border-color: #fca5a5; color: var(--bad-text); background: var(--bad-bg); }

.grade-sep { color: var(--text-faint); }
.as-of { color: var(--text-soft); font-size: 11px; }
/* An undated number is the one that ends up in a slide deck a year
   later with nobody able to say when it was true. Make its absence
   visible rather than letting it pass as clean. */
.as-of.undated {
    color: var(--warn-text);
    background: var(--warn-bg);
    padding: 0 5px;
    border-radius: 3px;
    font-weight: 600;
}
.stat-note {
    margin-top: 5px;
    font-size: 11.5px;
    color: var(--text-soft);
    line-height: 1.45;
}
.stat-cite {
    align-self: flex-start;
    margin-top: 7px;
    padding: 3px 9px;
    border-radius: 4px;
    border: 1px solid var(--border-strong);
    background: var(--bg);
    color: var(--text-soft);
    font-family: var(--sans);
    font-size: 11px;
    cursor: pointer;
}
.stat-cite:hover { background: var(--bg-muted); color: var(--text); }


/* ========== PROGRESS + SKELETONS ==========
   "loading…" with no end is indistinguishable from a hang. */

.tracker-progress {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 13px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-soft);
    font-size: 12.5px;
    color: var(--text-soft);
}
.tracker-progress.finished,
.tracker-progress.failed { flex-direction: row; align-items: center; gap: 8px; }
.tracker-progress.failed { background: var(--bad-bg); border-color: #fca5a5; }
.tracker-progress.stalled { background: var(--warn-bg); border-color: #fcd34d; }
.tp-head { display: flex; align-items: center; gap: 8px; }
.tp-label { font-weight: 600; color: var(--text); }
.tp-count { color: var(--text-soft); font-variant-numeric: tabular-nums; }
.tp-pct { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--text-muted); }
.tp-note { color: var(--text-muted); font-size: 11.5px; }
.tp-stall { color: var(--warn-text); font-size: 11.5px; font-weight: 500; }
.tp-reason { color: var(--bad-text); }
.tp-tick { color: var(--good-text); font-weight: 700; }
.tp-cross { color: var(--bad-text); font-weight: 700; }
.tp-retry {
    margin-left: auto;
    padding: 4px 11px;
    border-radius: 4px;
    border: 1px solid var(--border-strong);
    background: var(--bg);
    font-family: var(--sans);
    font-size: 12px;
    cursor: pointer;
}
.tp-bar {
    height: 5px;
    border-radius: 3px;
    background: var(--bg-muted);
    overflow: hidden;
}
.tp-fill {
    height: 100%;
    background: var(--accent);
    border-radius: 3px;
    transition: width 0.25s ease-out;
}
.tp-bar.indeterminate .tp-fill {
    width: 35%;
    animation: tp-slide 1.4s ease-in-out infinite;
}
@keyframes tp-slide {
    0% { margin-left: -35%; }
    100% { margin-left: 100%; }
}

/* Two shapes: skeleton rows inside a real <tbody> stay table rows and
   inherit the table's cell padding; the standalone <div> variant lays
   its own cells out. Never `display: contents` on a <tr> — that removes
   the row box and the cells collapse. */
div.skel-row {
    display: flex;
    gap: 14px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
}
div.skel-row .skel-cell { flex: 1; min-width: 0; }
.skel-bar {
    display: block;
    height: 11px;
    border-radius: 3px;
    background: linear-gradient(90deg, var(--bg-muted) 25%, var(--border) 50%, var(--bg-muted) 75%);
    background-size: 200% 100%;
    animation: skel-shimmer 1.3s linear infinite;
}
@keyframes skel-shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}


/* ========== MOBILE — verified at 375px ========== */
@media (max-width: 900px) {
    /* .table-wrap clips with overflow:hidden for its rounded corners,
       which on a phone means wide tables are simply cut off. Scroll
       them instead. */
    .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}
@media (max-width: 560px) {
    .wrap { padding: 16px 14px 60px; }
    .site-head { padding: 16px 14px 0; }
    .stats { grid-template-columns: 1fr; gap: 8px; }
    .controls { gap: 6px; }
    .controls input[type="search"] { min-width: 0; flex: 1 1 100%; }
    .controls select, .controls .btn { flex: 1 1 auto; }
    .brand h1 { font-size: 19px; }
    .src-banner { flex-wrap: wrap; }
    .src-banner-retry { align-self: stretch; width: 100%; }
    .citation-item { grid-template-columns: 1fr; gap: 6px; }
    .ov-grid { grid-template-columns: 1fr; gap: 2px; }
    .ov-grid dt { padding-top: 9px; }
    .detail-tabs { overflow-x: auto; }
    tr.detail-row .detail { padding: 14px 14px 16px; }
}

/* Windows high-contrast: the level glyphs are the only cue left once
   backgrounds are forced, so keep them and the borders. */
@media (forced-colors: active) {
    .src-banner { border: 2px solid; }
    .src-banner-glyph { border: 1px solid; }
    .fig-unavailable, .fig-partial { border-bottom: 1px dashed; }
    a:focus-visible, button:focus-visible, [tabindex]:focus-visible {
        outline: 3px solid Highlight;
    }
}
