/*
 * Hub layout and the glue between Echo components and native elements.
 * Component geometry lives in echo-components.css and colours in echo-tokens.css, both copied
 * from docs/design by `just design_sync`; this file only adds what the hub needs around them.
 */

/* ---------- Fonts (IBM Plex, OFL; bundled, never fetched from a CDN) ---------- */
@font-face { font-family: "IBM Plex Sans"; font-style: normal; font-weight: 100 700; font-stretch: 75% 100%; font-display: swap; src: url("../fonts/IBMPlexSans-Variable.woff2") format("woff2"); }
@font-face { font-family: "IBM Plex Sans"; font-style: italic; font-weight: 100 700; font-stretch: 75% 100%; font-display: swap; src: url("../fonts/IBMPlexSans-Italic-Variable.woff2") format("woff2"); }
@font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400; font-display: swap; src: url("../fonts/IBMPlexMono-Regular.woff2") format("woff2"); }
@font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 500; font-display: swap; src: url("../fonts/IBMPlexMono-Medium.woff2") format("woff2"); }
@font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 600; font-display: swap; src: url("../fonts/IBMPlexMono-SemiBold.woff2") format("woff2"); }

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; min-height: 100vh; display: flex; flex-direction: column;
  background: var(--canvas); color: var(--ink);
  font: 400 14px/20px var(--font-sans); -webkit-font-smoothing: antialiased;
}
h1, h2, h3, p { margin: 0; }
a { color: var(--brand-ink); text-underline-offset: 3px; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
a.echo-btn { text-decoration: none; }
[hidden] { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.is-mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.is-muted { color: var(--ink-muted); }

/* ---------- App shell ---------- */
.hub-topbar { position: sticky; top: 0; z-index: 10; padding: 0 var(--space-4); }
.hub-topbar nav { display: flex; align-items: center; gap: var(--space-1); }
.hub-topbar .echo-logo { flex: none; }
.hub-account { gap: var(--space-1-5); }
.hub-main { flex: 1; width: 100%; min-width: 0; max-width: 1280px; margin: 0 auto; padding: var(--space-6) var(--space-8) var(--space-10); }
.hub-footer {
  display: flex; justify-content: center; padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--line); font: 400 12px/16px var(--font-mono); color: var(--ink-muted);
}

/* ---------- Page header: crumbs, title, one fact line, quiet actions ---------- */
.hub-pagehead {
  display: grid; gap: var(--space-1); margin-bottom: var(--space-6);
  padding-bottom: var(--space-4); border-bottom: 1px solid var(--line);
}
.hub-pagehead__row { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--space-3) var(--space-6); }
.hub-pagehead__title { display: grid; gap: var(--space-0-5); min-width: 0; }
.hub-pagehead h1 { font: 600 22px/28px var(--font-sans); overflow-wrap: anywhere; }
.hub-facts { font: 400 13px/20px var(--font-mono); font-variant-numeric: tabular-nums; color: var(--ink-muted); }
.hub-facts b { font-weight: 400; color: var(--ink); }
.hub-crumbs a { color: var(--ink-muted); text-decoration: none; }
.hub-crumbs a:hover { color: var(--ink); text-decoration: underline; }

/* ---------- Data tables ---------- */
.hub-table-wrap { position: relative; overflow-x: auto; }
.echo-table th.is-num { font: 500 11px/16px var(--font-sans); letter-spacing: 0.08em; }
.echo-table th.is-actions, .echo-table td.is-actions { width: 1%; text-align: right; white-space: nowrap; }
.echo-table td.is-actions { padding-top: var(--space-1); padding-bottom: var(--space-1); }
.echo-table td.is-actions .echo-btn + .echo-btn { margin-left: var(--space-1); }
.echo-table td { vertical-align: top; }
.echo-table td.is-actions, .echo-table td.is-middle { vertical-align: middle; }
.hub-cell-name { font-weight: 500; }
.hub-cell-sub { margin-top: var(--space-0-5); max-width: var(--measure); font: 400 12px/16px var(--font-sans); color: var(--ink-muted); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.hub-pills { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.hub-empty {
  display: grid; gap: var(--space-2); justify-items: start; padding: var(--space-6);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-md); color: var(--ink-muted);
}

/* ---------- Forms ---------- */
.hub-form { display: grid; gap: var(--space-4); }
.hub-form--narrow { max-width: 560px; }
.hub-form fieldset { display: grid; gap: var(--space-4); margin: 0; padding: 0; border: 0; min-width: 0; }
.hub-form fieldset + fieldset { padding-top: var(--space-5); border-top: 1px solid var(--line); }
.hub-form legend { float: left; width: 100%; padding: 0; }
.hub-form legend + * { clear: both; }
.hub-form .echo-section { padding-bottom: 0; }
.hub-form__row { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-4); }
.hub-form__actions { display: flex; justify-content: flex-end; gap: var(--space-2); }
.hub-inline { display: flex; gap: var(--space-2); align-items: center; }
.hub-inline > .echo-input { flex: 1; min-width: 0; }
.echo-label .is-muted { font-weight: 400; }
textarea.echo-input { height: auto; min-height: 64px; padding: var(--space-1-5) var(--space-2); resize: vertical; }
select.echo-input { padding-right: var(--space-1); }
/* Browsers match :read-only on every select; only real read-only text fields are sunken. */
select.echo-input:read-only { background: var(--surface); }
select.echo-input[multiple] { height: auto; min-height: 96px; padding: var(--space-1); }
select.echo-input[multiple] option { padding: var(--space-0-5) var(--space-1); border-radius: var(--radius-xs); }
.echo-input.is-code { font: 400 13px/20px var(--font-mono); }
.hub-check { display: flex; align-items: flex-start; gap: var(--space-2); font: 500 13px/18px var(--font-sans); }
.hub-check input { width: 16px; height: 16px; margin: 1px 0 0; accent-color: var(--brand); flex: none; }
.hub-check + .echo-help { padding-left: var(--space-6); }
/* A checkbox that reveals the fields it governs; CSS alone, so it works without a script. */
.hub-reveal { display: grid; gap: var(--space-3); }
.hub-reveal__body { display: grid; gap: var(--space-3); padding-left: var(--space-6); }
.hub-reveal:not(:has(> .hub-check input:checked)) > .hub-reveal__body { display: none; }
.hub-errors { display: grid; gap: var(--space-1); margin: 0; padding: var(--space-2) var(--space-3); list-style: none; background: var(--danger-soft); color: var(--danger); border-radius: var(--radius-sm); font: 400 13px/18px var(--font-sans); }

/* ---------- Panels as page sections ---------- */
.hub-panel { max-width: 720px; margin-bottom: var(--space-4); }
/* Settings that most projects never change, collapsed under a section label. */
.hub-advanced { max-width: 720px; }
.hub-advanced > summary { justify-content: flex-start; align-items: center; gap: var(--space-1-5); margin-bottom: var(--space-2); padding: var(--space-1) 0; cursor: pointer; list-style: none; }
.hub-advanced > summary::-webkit-details-marker { display: none; }
.hub-advanced > summary:hover .echo-section__title { color: var(--ink); }
.hub-advanced > summary:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: var(--radius-xs); }
.hub-advanced > summary .echo-section__meta { margin-left: var(--space-2); }
.hub-advanced__caret { color: var(--ink-muted); }
.hub-advanced[open] .hub-advanced__caret { transform: rotate(90deg); }
.hub-panel .echo-panel__body > p + p { margin-top: var(--space-2); }
.hub-panel .echo-table { border: 0; }

/* ---------- Menus on the native Popover API (hub.js positions them by their trigger) ---------- */
.echo-menu[popover] { position: fixed; inset: auto; margin: 0; color: var(--ink); overflow: auto; max-height: calc(100vh - 16px); }
.echo-menu form { margin: 0; }
.echo-menu__item { width: 100%; border: 0; background: none; text-align: left; text-decoration: none; cursor: pointer; }
.echo-menu__item:hover, .echo-menu__item:focus-visible { background: var(--surface-sunken); outline: none; }
.echo-menu__item[aria-current="page"] { color: var(--brand-ink); font-weight: 500; }
.echo-menu__item[aria-current="page"] svg { color: var(--brand-ink); }
.echo-menu__item.echo-cat-teal svg, .echo-menu__item.echo-cat-green svg, .echo-menu__item.echo-cat-red svg { color: var(--cat); }
.echo-menu__meta { padding: var(--space-1-5) var(--space-2); font: 400 12px/16px var(--font-sans); color: var(--ink-muted); overflow-wrap: anywhere; }

/* ---------- Dialogs on the native <dialog> element ---------- */
dialog.echo-dialog { margin: auto; color: var(--ink); max-height: calc(100vh - var(--space-8)); overflow: auto; }
dialog.echo-dialog--form { max-width: 560px; }
dialog.echo-dialog::backdrop { background: rgb(12 18 24 / 0.45); }
dialog.echo-dialog[open] { animation: hub-rise 150ms ease-out; }
.hub-dialog__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-4); }
.hub-dialog__head .echo-btn { margin: calc(var(--space-1) * -1) calc(var(--space-2) * -1) 0 0; }
.echo-dialog__footer { align-items: center; }
.hub-dialog__note { flex: 1; font: 400 12px/16px var(--font-sans); color: var(--ink-muted); }
.hub-dialog__note--warn { display: flex; align-items: flex-start; gap: var(--space-2); font-size: 13px; line-height: 18px; color: var(--ink); }
.hub-dialog__note--warn svg { flex: none; width: var(--size-icon-md); height: var(--size-icon-md); margin-top: 1px; color: var(--review); }
/* An upload in flight already posted its files; the zone stays visible but takes no more. */
dialog[data-busy] .echo-dropzone { opacity: 0.6; pointer-events: none; }
.hub-dialog__note--warn strong { font-weight: 600; }
@keyframes hub-rise { from { opacity: 0; transform: translateY(4px); } }

/* ---------- Toasts (Django messages) ---------- */
.hub-toasts { position: fixed; right: var(--space-4); bottom: var(--space-4); z-index: 30; display: grid; gap: var(--space-2); max-width: calc(100vw - var(--space-8)); }
.echo-toast { animation: hub-rise 150ms ease-out; }
.echo-toast--warning svg { color: var(--review); }
.echo-toast .echo-btn--icon svg { width: var(--size-icon-md); height: var(--size-icon-md); color: inherit; }

/* ---------- Busy state for in-request work (TMX ingest) ---------- */
.echo-btn > span:not([hidden]) { display: inline-flex; align-items: center; gap: var(--space-1-5); }
.hub-spin { animation: hub-spin 900ms linear infinite; }
@keyframes hub-spin { to { transform: rotate(360deg); } }

/* ---------- Sign-in and other entrance pages (showcase register) ---------- */
.hub-entrance { display: grid; justify-items: center; gap: var(--space-6); max-width: 420px; margin: var(--space-10) auto 0; }
.hub-entrance > .echo-logo svg { height: 40px; }
.hub-entrance__card { width: 100%; display: grid; gap: var(--space-5); padding: var(--space-8); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); }
.hub-entrance__card h1 { font: 600 40px/44px var(--font-sans); font-variation-settings: "wdth" 85; letter-spacing: -0.01em; }
.hub-entrance__card .echo-input { height: var(--size-control-lg); }
.hub-entrance__card .echo-btn { width: 100%; height: var(--size-control-lg); font-size: 15px; }
.hub-entrance__alt { display: grid; gap: var(--space-2); padding-top: var(--space-5); border-top: 1px solid var(--line); }

/* ---------- allauth pages (rendered through the allauth/elements overrides) ---------- */
.hub-allauth { display: grid; gap: var(--space-4); align-content: start; }
.hub-allauth > p { color: var(--ink-muted); max-width: var(--measure); }
.hub-allauth > h2 { font: 600 18px/24px var(--font-sans); }
.hub-manage { max-width: 720px; }
.hub-manage > h1 { font: 600 22px/28px var(--font-sans); padding-bottom: var(--space-4); border-bottom: 1px solid var(--line); }
.hub-manage .hub-form__actions { justify-content: flex-start; }
.hub-rule { width: 100%; margin: 0; border: 0; border-top: 1px solid var(--line); }
.hub-notice { display: flex; gap: var(--space-2); padding: var(--space-3); background: var(--brand-soft); border-radius: var(--radius-md); }
.hub-notice svg { color: var(--brand-ink); margin-top: 2px; }
.hub-notice--warn { background: var(--review-soft); }
.hub-notice--warn svg { color: var(--review); }
.hub-notice strong { font-weight: 600; }
.hub-providers { flex-wrap: wrap; }

/* ---------- Analysis: metrics strip, bucket grid, earlier snapshots ---------- */
.echo-actions > form { display: contents; }
.hub-analysis-notice { margin-bottom: var(--space-4); font: 400 13px/20px var(--font-sans); }
.hub-analysis-notice svg { flex: none; width: var(--size-icon-md); height: var(--size-icon-md); }
.hub-analysis-metrics { margin-bottom: var(--space-6); }
.hub-analysis-section { margin-bottom: var(--space-6); }
.hub-analysis th[scope="row"], .hub-analysis th[scope="rowgroup"] { background: transparent; }
.hub-analysis th[scope="rowgroup"] { vertical-align: top; min-width: 12rem; text-transform: none; letter-spacing: 0; font: 500 13px/20px var(--font-sans); color: var(--ink); }
.hub-analysis th[scope="rowgroup"].is-code { font: 400 13px/20px var(--font-mono); }
.hub-analysis th[scope="rowgroup"] .hub-cell-sub { display: block; font-family: var(--font-sans); }
.hub-analysis thead tr:first-child th { border-bottom: 0; padding-bottom: var(--space-1); }
.hub-analysis thead th { white-space: nowrap; }
.hub-analysis__rates th, .hub-analysis__rates td { padding-top: 0; }
/* .echo-table drops the rule under each section's last row (tr:last-child matches per section).
   The grid wants one under the rates and a stronger one above the total, across every column;
   both sit on the bottom edge of the row above, because a collapsed border shared with the
   cell above would otherwise take that cell's colour. */
.hub-analysis thead tr:last-child > * { border-bottom: 1px solid var(--line); }
.hub-analysis tbody tr:last-child > *,
.hub-analysis tbody tr:nth-last-child(2) > th[rowspan] { border-bottom: 1px solid var(--line-strong); }
.hub-analysis__rates td.is-num { font-size: 11px; line-height: 16px; color: var(--ink-faint); }
/* A file's two rows read as one block: the rule falls under Weighted only. */
.hub-analysis__raw td, .hub-analysis__raw th[scope="row"] { border-bottom-color: transparent; }
.hub-analysis__weighted td.is-num { color: var(--ink); }
.hub-analysis td.is-num.is-zero { color: var(--ink-faint); }
.hub-analysis td.is-total { color: var(--ink); font-weight: 600; }
.hub-analysis tfoot tr:last-child > * { border-bottom: 0; }
.hub-snapshots { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-md); }
.hub-snapshot + .hub-snapshot { border-top: 1px solid var(--line); }
.hub-snapshot > summary {
  display: grid; grid-template-columns: 16px minmax(9rem, 1fr) minmax(8rem, auto) minmax(10rem, auto) minmax(12rem, auto);
  align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); cursor: pointer; list-style: none;
  font: 400 13px/20px var(--font-mono); font-variant-numeric: tabular-nums; color: var(--ink-muted);
}
.hub-snapshot > summary::-webkit-details-marker { display: none; }
.hub-snapshot > summary:hover { background: var(--row-alt); }
.hub-snapshot > summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.hub-snapshot[open] > summary { border-bottom: 1px solid var(--line); }
.hub-snapshot[open] .hub-snapshot__caret { transform: rotate(90deg); }
.hub-snapshot__figure b { font-weight: 400; color: var(--ink); }
.hub-snapshot__flags { display: flex; justify-content: flex-end; gap: var(--space-1); }
.hub-snapshot__body { padding: var(--space-3); }
.hub-settings-grid { min-height: 20rem; }

/* ---------- Small screens ---------- */
@media (max-width: 720px) {
  .hub-main { padding: var(--space-4) var(--space-4) var(--space-8); }
  .hub-topbar { padding: 0 var(--space-2); gap: var(--space-2); }
  .hub-topbar .echo-topbar__sep, .hub-account__name { display: none; }
  .hub-navlabel { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .hub-entrance { margin-top: var(--space-4); }
  .hub-entrance__card { padding: var(--space-5); }
  .hub-entrance__card h1 { font-size: 28px; line-height: 34px; }
  .hub-snapshot > summary { grid-template-columns: 16px 1fr; row-gap: var(--space-0-5); }
  .hub-snapshot > summary > :not(svg) { grid-column: 2; }
  .hub-snapshot__flags { justify-content: flex-start; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}
