/* Runova — design system
 *
 * Dark first. The palette is committed to rather than mirrored from the
 * operating system: a training app is read at dawn and after dark, and a
 * dark surface makes maps and charts carry. A light theme is available by
 * choice, stored locally, but nobody is thrown into it by their device.
 *
 * Everything below is a token. Screens compose tokens; no screen invents a
 * colour or a spacing value of its own. That is what keeps a fifth feature
 * from looking like it was bolted on by somebody else.
 */

:root {
  /* Surfaces, darkest to lightest. */
  --bg:            #080b11;
  --surface:       #10151e;
  --surface-2:     #161d29;
  --surface-3:     #1e2735;
  --border:        #232d3d;
  --border-strong: #313d50;

  --text:          #e9eef6;
  --text-dim:      #9aa7bb;
  --text-faint:    #64718a;

  /* One accent, used for anything the athlete acts on or achieves. */
  --accent:        #2ee6c5;
  --accent-hot:    #5bf5da;
  --accent-dim:    #17a894;
  --accent-glow:   rgba(46, 230, 197, 0.14);
  --on-accent:     #04120f;

  /* Data channels. Each sensor keeps its colour everywhere it appears, so
     the reader learns the mapping once. */
  --c-pace:        #2ee6c5;
  --c-hr:          #ff5f6d;
  --c-elev:        #a78bfa;
  --c-power:       #fb923c;
  --c-cadence:     #60a5fa;

  --good:          #34d399;
  --warn:          #fbbf24;
  --bad:           #f87171;

  /* Type. One family, weights doing the work. Numerals are tabular so
     columns of times and distances line up instead of dancing. */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --num: "SF Mono", ui-monospace, "Roboto Mono", Menlo, monospace;

  --fs-hero:  clamp(28px, 8vw, 40px);
  --fs-xl:    clamp(20px, 5vw, 26px);
  --fs-lg:    17px;
  --fs-md:    15px;
  --fs-sm:    13px;
  --fs-xs:    11.5px;

  /* Spacing on a 4px grid. */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px;

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-full: 999px;

  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 4px 16px rgba(0,0,0,.3);

  /* Light maps are inverted rather than swapped for a dark basemap: the
     tile provider has no dark style, and a bright rectangle in the middle
     of a dark page is worse than an approximation. */
  --map-filter: invert(1) hue-rotate(180deg) brightness(.92) contrast(.88) saturate(.7);

  color-scheme: dark;
}

:root[data-theme="light"] {
  --bg:            #f5f7fa;
  --surface:       #ffffff;
  --surface-2:     #ffffff;
  --surface-3:     #eef1f6;
  --border:        #dfe4ec;
  --border-strong: #c6cedb;

  --text:          #10151e;
  --text-dim:      #5a6675;
  --text-faint:    #8c98a8;

  --accent:        #0d9488;
  --accent-hot:    #0f766e;
  --accent-glow:   rgba(13, 148, 136, 0.10);
  --on-accent:     #ffffff;

  --c-pace:        #0d9488;
  --c-hr:          #dc2626;
  --c-elev:        #7c3aed;
  --c-power:       #ea580c;
  --c-cadence:     #2563eb;

  --shadow: 0 1px 2px rgba(16,21,30,.06), 0 4px 14px rgba(16,21,30,.06);
  --map-filter: none;

  color-scheme: light;
}

/* ---------- base ---------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-md);
  line-height: 1.5;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  /* Room for the bottom bar on phones with a home indicator. */
  padding-bottom: env(safe-area-inset-bottom);
}

h1, h2, h3 { margin: 0; font-weight: 650; letter-spacing: -0.01em; }

button, input, select { font: inherit; color: inherit; }

a { color: var(--accent); }

::selection { background: var(--accent-glow); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

.num { font-family: var(--num); font-variant-numeric: tabular-nums; }

/* ---------- app frame ---------- */

.app { display: none; }
.app.ready { display: block; }

.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) var(--s4);
  padding-top: calc(var(--s3) + env(safe-area-inset-top));
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border);
}

.brand {
  font-size: var(--fs-lg); font-weight: 750;
  letter-spacing: -0.03em;
}
.brand em { color: var(--accent); font-style: normal; }

.grow { flex: 1; }

.iconbtn {
  display: grid; place-items: center;
  width: 36px; height: 36px; padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.iconbtn:hover { border-color: var(--border-strong); background: var(--surface-2); }
.iconbtn svg { width: 17px; height: 17px; stroke: var(--text-dim); fill: none;
               stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.iconbtn:hover svg { stroke: var(--text); }

.btn {
  display: inline-flex; align-items: center; gap: var(--s2);
  padding: 9px 15px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  font-size: var(--fs-sm); font-weight: 600;
  cursor: pointer;
  transition: border-color .15s, background .15s, transform .06s;
}
.btn:hover { border-color: var(--border-strong); background: var(--surface-2); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: default; transform: none; }

.btn-primary {
  background: var(--accent); border-color: var(--accent);
  color: var(--on-accent);
}
.btn-primary:hover { background: var(--accent-hot); border-color: var(--accent-hot); }

.wrap {
  max-width: 1180px; margin: 0 auto;
  padding: var(--s4);
}

/* ---------- summary strip ---------- */

.summary {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  margin-bottom: var(--s4);
}
.summary .cell { background: var(--surface); padding: var(--s3) var(--s4); }
.summary b {
  display: block;
  font-size: clamp(17px, 4.4vw, 24px); font-weight: 700;
  font-family: var(--num); font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em; line-height: 1.15;
}
.summary span {
  font-size: var(--fs-xs); color: var(--text-faint);
  text-transform: uppercase; letter-spacing: .06em; font-weight: 600;
}

/* ---------- sport filter ---------- */

.chips {
  display: flex; gap: var(--s2);
  overflow-x: auto; padding-bottom: var(--s2);
  margin-bottom: var(--s3);
  scrollbar-width: none;
}
.chips::-webkit-scrollbar { display: none; }

.chip {
  flex: none;
  padding: 6px 13px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-dim);
  cursor: pointer; white-space: nowrap;
  transition: all .15s;
}
.chip:hover { border-color: var(--border-strong); color: var(--text); }
.chip[aria-pressed="true"] {
  background: var(--accent-glow);
  border-color: var(--accent);
  color: var(--accent);
}

/* ---------- activity list ---------- */

.list { display: grid; gap: var(--s3); }

.card {
  display: block; width: 100%; text-align: left;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  cursor: pointer;
  transition: border-color .15s, background .15s, transform .08s;
}
.card:hover { border-color: var(--border-strong); background: var(--surface-2); }
.card:active { transform: scale(.995); }
.card[aria-selected="true"] {
  border-color: var(--accent);
  background: var(--surface-2);
  box-shadow: inset 3px 0 0 var(--accent);
}

.card-head { display: flex; align-items: center; gap: var(--s3); }

.sport {
  flex: none; display: grid; place-items: center;
  width: 38px; height: 38px;
  border-radius: var(--r-sm);
  background: var(--surface-3);
  color: var(--accent);
}

.sport-inline {
  display: inline-grid; place-items: center;
  vertical-align: -3px; color: var(--accent);
}

.chip { display: inline-flex; align-items: center; gap: 6px; }
.chip svg { width: 15px; height: 15px; }

.card-title { min-width: 0; flex: 1; }
.card-title h3 {
  font-size: var(--fs-md); font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.card-title time { font-size: var(--fs-xs); color: var(--text-faint); }

.card-stats {
  display: flex; gap: var(--s4);
  margin-top: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--border);
}
.card-stats div { min-width: 0; }
.card-stats b {
  display: block; font-size: var(--fs-md); font-weight: 650;
  font-family: var(--num); font-variant-numeric: tabular-nums;
}
.card-stats span {
  font-size: 10px; color: var(--text-faint);
  text-transform: uppercase; letter-spacing: .05em; font-weight: 600;
}

/* ---------- detail ---------- */

.detail {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}

.detail-head { padding: var(--s4); }
.detail-head h2 { font-size: var(--fs-xl); margin-bottom: var(--s1); }
.detail-head .meta {
  font-size: var(--fs-xs); color: var(--text-faint);
  display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3);
}

#map {
  height: 260px;
  background: var(--surface-3);
  filter: var(--map-filter);
}
/* Controls and markers must not be inverted along with the tiles. */
#map .maplibregl-ctrl-group,
#map .maplibregl-marker,
#map .maplibregl-ctrl-attrib { filter: var(--map-filter); }

/* The gap is drawn by letting the container colour show through, which
   means a row that does not fill would leave a bare stripe. Painting the
   container in the surface colour instead makes an incomplete last row
   read as deliberate space rather than a missing tile. */
.metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
  gap: 1px;
  background: var(--surface);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.metrics div {
  background: var(--surface);
  box-shadow: 1px 0 0 var(--border), 0 1px 0 var(--border);
}
.metrics div { padding: var(--s3) var(--s4); }
.metrics b {
  display: block;
  font-size: var(--fs-lg); font-weight: 700;
  font-family: var(--num); font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.metrics span {
  font-size: 10px; color: var(--text-faint);
  text-transform: uppercase; letter-spacing: .05em; font-weight: 600;
}

.charts { padding: var(--s4); display: grid; gap: var(--s4); }
.chart h4 {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--fs-xs); font-weight: 700; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: .07em;
  margin: 0 0 var(--s2);
}
.chart h4 em {
  font-style: normal; font-weight: 600;
  font-family: var(--num); letter-spacing: 0;
  text-transform: none; font-size: var(--fs-sm);
}
.chart svg { display: block; width: 100%; height: 74px; overflow: visible; }

/* ---------- states ---------- */

.empty {
  padding: var(--s7) var(--s4);
  text-align: center; color: var(--text-dim);
}
.empty .big { font-size: 38px; margin-bottom: var(--s3); opacity: .7; }
.empty h3 { font-size: var(--fs-lg); margin-bottom: var(--s2); color: var(--text); }
.empty p { margin: 0 auto; max-width: 42ch; font-size: var(--fs-sm); }

.skeleton {
  border-radius: var(--r-md);
  background: linear-gradient(90deg,
    var(--surface) 25%, var(--surface-3) 50%, var(--surface) 75%);
  background-size: 400% 100%;
  animation: shimmer 1.3s ease-in-out infinite;
}
@keyframes shimmer { to { background-position: -200% 0; } }

/* ---------- upload ---------- */

.drop {
  padding: var(--s5) var(--s4);
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--r-md);
  text-align: center; color: var(--text-faint);
  font-size: var(--fs-sm);
  transition: border-color .15s, background .15s, color .15s;
}
.drop.over {
  border-color: var(--accent); color: var(--accent);
  background: var(--accent-glow);
}

.log { display: grid; gap: var(--s1); margin-top: var(--s3); font-size: var(--fs-sm); }
.log div { display: flex; gap: var(--s2); }
.log .ok  { color: var(--good); }
.log .dup { color: var(--text-faint); }
.log .err { color: var(--bad); }

/* ---------- sign-in gate ---------- */

.gate {
  position: fixed; inset: 0; z-index: 100;
  display: none; align-items: center; justify-content: center;
  padding: var(--s4);
  background: var(--bg);
  overflow-y: auto;
}
.gate.show { display: flex; }

.gate-card {
  width: 100%; max-width: 380px;
  padding: var(--s5);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.gate-card .brand { font-size: var(--fs-hero); display: block; margin-bottom: var(--s1); }
.gate-lead { color: var(--text-dim); font-size: var(--fs-sm); margin-bottom: var(--s5); }

.field { margin-bottom: var(--s3); }
.field label {
  display: block; font-size: var(--fs-sm); font-weight: 600;
  margin-bottom: 5px;
}
.field label small { font-weight: 400; color: var(--text-faint); }
.field input {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg);
  transition: border-color .15s;
}
.field input:focus { outline: none; border-color: var(--accent); }
.field .hint { font-size: var(--fs-xs); color: var(--text-faint); margin-top: 4px; }

.gate-card .btn { width: 100%; justify-content: center; margin-top: var(--s4); }

.gate-switch {
  margin-top: var(--s4); text-align: center;
  font-size: var(--fs-sm); color: var(--text-dim);
}
.gate-switch a { cursor: pointer; font-weight: 600; }

.alert {
  margin-top: var(--s3);
  padding: 9px 12px;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  background: color-mix(in srgb, var(--bad) 14%, transparent);
  color: var(--bad);
}

/* ---------- responsive ---------- */

/* Four across only while the summary has the full width of the page.
   Once the two-column layout puts it in a 370px rail it goes back to a
   2x2 block — a viewport-width query would widen it exactly when its
   container got narrower, which is how the totals ended up clipped. */
@media (min-width: 560px) and (max-width: 899px) {
  .summary { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 560px) {
  #map { height: 320px; }
}
/* No four-across rule above 900px: the layout puts the summary in a
   fixed 370px rail there, so a wider window makes its container no wider. */

@media (min-width: 900px) {
  .wrap {
    display: grid;
    grid-template-columns: 370px minmax(0, 1fr);
    gap: var(--s4);
    align-items: start;
    padding: var(--s4) var(--s5) var(--s7);
  }
  .col-left { position: sticky; top: 74px; }
  .list { max-height: calc(100vh - 340px); overflow-y: auto; padding-right: 2px; }
  #map { height: 380px; }
}

/* The list scrolls on desktop; on a phone the page scrolls instead. */
@media (max-width: 899px) {
  .col-right:not(.open) { display: none; }
  .col-right.open {
    position: fixed; inset: 0; z-index: 30;
    background: var(--bg);
    overflow-y: auto;
    padding-bottom: env(safe-area-inset-bottom);
  }
  .col-right.open .detail { border: 0; border-radius: 0; }
  .backlink {
    position: sticky; top: 0; z-index: 2;
    display: flex; align-items: center; gap: var(--s2);
    padding: var(--s3) var(--s4);
    padding-top: calc(var(--s3) + env(safe-area-inset-top));
    background: color-mix(in srgb, var(--bg) 88%, transparent);
    backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--border);
    font-size: var(--fs-sm); font-weight: 600;
    cursor: pointer;
  }
}
@media (min-width: 900px) {
  .backlink { display: none; }
}

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


/* ---------- recording ---------- */

.record {
  position: fixed; inset: 0; z-index: 90;
  display: none; align-items: flex-end; justify-content: center;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(8px);
}
.record.show { display: flex; }

.record-sheet {
  width: 100%; max-width: 460px;
  max-height: 92vh; overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--surface);
  box-shadow: var(--shadow);
  padding-bottom: env(safe-area-inset-bottom);
}
@media (min-width: 560px) {
  .record { align-items: center; }
  .record-sheet { border-radius: var(--r-lg); }
}

.record-head {
  display: flex; align-items: center; gap: var(--s2);
  padding: var(--s4);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-sm);
}

/* A recording in progress needs to be obvious from across a room, and
   obviously stopped when it is paused. */
.rec-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--bad);
  animation: pulse 1.6s ease-in-out infinite;
}
.record[data-paused="true"] .rec-dot {
  background: var(--warn); animation: none;
}
@keyframes pulse { 50% { opacity: .25; } }

.record-body { padding: var(--s5) var(--s4); }

.rec-live { text-align: center; }
.rec-time {
  font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: clamp(46px, 15vw, 68px); font-weight: 700;
  letter-spacing: -0.03em; line-height: 1;
}
.rec-signal {
  display: inline-block; margin-top: var(--s3);
  padding: 4px 11px; border-radius: var(--r-full);
  font-size: var(--fs-xs); font-weight: 600;
  background: var(--surface-3); color: var(--text-dim);
}
.rec-signal[data-quality="good"] { color: var(--good); }
.rec-signal[data-quality="weak"] { color: var(--warn); }
.rec-signal[data-quality="bad"],
.rec-signal[data-quality="seeking"] { color: var(--text-faint); }

.rec-grid, .rec-summary {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--s2); margin-top: var(--s5);
}
.rec-summary { margin: 0 0 var(--s5); }
.rec-grid div, .rec-summary div {
  padding: var(--s3) var(--s2);
  border-radius: var(--r-sm);
  background: var(--surface-3);
  text-align: center;
}
.rec-grid b, .rec-summary b {
  display: block;
  font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: var(--fs-xl); font-weight: 700; line-height: 1.15;
}
.rec-grid span, .rec-summary span {
  font-size: 10px; color: var(--text-faint);
  text-transform: uppercase; letter-spacing: .05em; font-weight: 600;
}

.rec-warn {
  margin: var(--s5) 0 0;
  padding: var(--s3);
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--warn) 12%, transparent);
  color: var(--warn);
  font-size: var(--fs-xs); line-height: 1.45; text-align: left;
}

.record-actions {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2);
  padding: var(--s4);
  border-top: 1px solid var(--border);
}
.record-actions .btn { justify-content: center; }

.record-body .alert, .record .alert { margin: 0 var(--s4) var(--s4); }


/* ---------- sharing ---------- */

.share {
  padding: var(--s4);
  border-bottom: 1px solid var(--border);
}
.share-row { display: flex; gap: var(--s2); flex-wrap: wrap; }
.share-hint {
  margin: var(--s3) 0 0;
  font-size: var(--fs-sm); color: var(--text-dim);
}
.share-link {
  display: flex; gap: var(--s2); margin-top: var(--s3);
}
.share-link input {
  flex: 1; min-width: 0;
  padding: 8px 11px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg); color: var(--text-dim);
  font-size: var(--fs-sm);
  font-family: var(--num);
}
.share-note {
  margin: var(--s3) 0 0;
  font-size: var(--fs-xs); color: var(--text-faint);
}

/* A visitor has no library and no toolbar. */
body.public .wrap { grid-template-columns: 1fr; }
body.public .col-right { position: static; }
