/* Swimlog — dark by design, one surface family, chart colours validated against it. */

:root {
  color-scheme: dark;

  --bg:            #0b0f14;
  --surface:       #151b23;
  --surface-2:     #1b232d;
  --border:        #232c38;
  --border-strong: #2f3a47;

  --text:          #e6edf3;
  --text-2:        #9aa0a6;
  --text-3:        #64717f;

  --accent:        #35d0ff;   /* interface identity: distances, links */
  --series:        #1e9fce;   /* chart slot 1 — validated on --surface */
  --rest:          #d95926;   /* chart slot 2 — rests, an event not a series */

  /* Sequential ramp for the activity calendar: one hue (the app's own accent), light meaning
     little and dark meaning a lot, mixed toward the surface rather than picked by eye so the
     four steps stay evenly spaced. Magnitude, not identity — never more than one hue here. */
  --heat-0: var(--surface-2);
  --heat-1: color-mix(in oklab, var(--accent) 25%, var(--surface-2));
  --heat-2: color-mix(in oklab, var(--accent) 50%, var(--surface-2));
  --heat-3: color-mix(in oklab, var(--accent) 75%, var(--surface-2));
  --heat-4: var(--accent);

  --radius:        .8rem;
  --radius-sm:     .45rem;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 1.5rem 1rem 5rem;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.55 system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-text-size-adjust: 100%;
}

main { max-width: 46rem; margin: 0 auto; }
a { color: var(--accent); }

/* ---------- masthead ---------- */

.masthead {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; margin-bottom: 1.25rem;
}
.masthead h1 { font-size: 1.35rem; margin: 0; letter-spacing: -.01em; }
.masthead h1 a { color: inherit; text-decoration: none; }
.masthead nav { display: flex; gap: .9rem; font-size: .85rem; }
.masthead nav a { color: var(--text-2); text-decoration: none; }
.masthead nav a:hover { color: var(--text); }

/* ---------- filter row: one row, above everything it scopes ---------- */

.filters { display: flex; gap: .4rem; margin-bottom: 1.25rem; flex-wrap: wrap; }
.filters a {
  padding: .3rem .7rem; border-radius: 999px; font-size: .85rem;
  text-decoration: none; color: var(--text-2);
  border: 1px solid var(--border); background: var(--surface);
}
.filters a:hover { color: var(--text); border-color: var(--border-strong); }
.filters a.is-on { color: var(--bg); background: var(--accent); border-color: var(--accent); font-weight: 600; }

/* ---------- stat tiles: the number is the chart ---------- */

.stats-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: .6rem; margin-bottom: 1.25rem;
}
.stat {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .8rem .9rem;
}
.stat-value {
  font-size: 1.5rem; font-weight: 700; line-height: 1.1; letter-spacing: -.02em;
  /* Proportional figures: tabular digits read loose at display sizes. */
}
.stat-label {
  color: var(--text-2); font-size: .78rem; text-transform: uppercase;
  letter-spacing: .05em; margin-top: .25rem;
}
.stat-note { color: var(--text-3); font-size: .78rem; margin-top: .15rem; }

/* ---------- charts ---------- */

.chart { margin: 1rem 0 .3rem; }
.chart-title {
  display: flex; align-items: center; gap: .4rem;
  color: var(--text-2); font-size: .78rem; letter-spacing: .05em;
  text-transform: uppercase; margin-bottom: .5rem;
}
.chart-unit { text-transform: none; letter-spacing: 0; color: var(--text-3); }

.chart-expand, #select-toggle {
  width: 1.6rem; height: 1.6rem; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 1px solid var(--border); color: var(--text-2);
  border-radius: var(--radius-sm); cursor: pointer; font-size: .85rem; line-height: 1;
}
.chart-expand { margin-left: auto; }
.chart-expand:hover, .chart-expand:focus-visible,
#select-toggle:hover, #select-toggle:focus-visible { color: var(--text); border-color: var(--border-strong); }
/* Left on when select mode is active, so the one button also shows the state it toggles. */
#select-toggle.is-active { color: var(--accent); border-color: var(--accent); background: rgba(53, 208, 255, .1); }

/* Expanded chart: fills the viewport so a phone screen's worth of height goes to the data
   instead of a fixed 190px box — the same markup, just given room. */
body.chart-lock { overflow: hidden; }
.chart.is-expanded {
  position: fixed; inset: 0; z-index: 50; margin: 0;
  background: var(--bg); padding: 1rem 1rem 1.5rem;
  display: flex; flex-direction: column;
}
.chart.is-expanded .chart-title { margin-bottom: 1rem; font-size: .85rem; }
.chart.is-expanded .chart-body { flex: 1; min-height: 0; }
.chart.is-expanded .ch-plot { height: 100%; }
.chart.is-expanded .trend-bars { flex: 1; height: auto; }
.chart.is-expanded .chart-axis { margin-bottom: .5rem; }

.chart-body { display: flex; gap: .5rem; }
.ch-gutter { position: relative; width: 2rem; flex: none; }
.ch-ylabel {
  position: absolute; right: 0; transform: translateY(-50%);
  color: var(--text-2); font-size: .7rem; font-variant-numeric: tabular-nums;
}
.ch-plot { position: relative; flex: 1; height: 190px; outline: none; }
.ch-plot:focus-visible { box-shadow: 0 0 0 2px var(--accent); border-radius: 2px; }
.ch-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* Hairline, solid, one shade off the surface. Never dashed — dashing is for annotation. */
.ch-grid { stroke: var(--border); stroke-width: 1; vector-effect: non-scaling-stroke; }
.ch-lap  { stroke: #354352; stroke-width: 1; opacity: .55; vector-effect: non-scaling-stroke; }
/* Alternating lap bands: enough to read the wall-to-wall rhythm, never competing with the line. */
.ch-band { fill: #ffffff; fill-opacity: .028; }
.ch-area { fill: var(--series); fill-opacity: .13; }
.ch-line {
  fill: none; stroke: var(--series); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke;
}
/* A rest's edges: warm and dashed so they never read as data. */
.ch-rest {
  stroke: var(--rest); stroke-width: 1.5; stroke-dasharray: 3 3; opacity: .8;
  vector-effect: non-scaling-stroke;
}
/* The rest itself is a real stretch of the timeline now — as wide as the break actually was,
   full height, the same visual weight as a work interval rather than a subtle accent. There is
   no HR line drawn through it (there is no reading to draw), so a stronger fill than the lap
   bands reads as its own state, not a variation on the swim it interrupts. */
.ch-restband { fill: var(--rest); fill-opacity: .16; }

.ch-lapnum {
  position: absolute; top: 3px; transform: translateX(-50%);
  color: var(--text-3); font-size: .62rem; font-weight: 600; pointer-events: none;
}
.ch-restlabel {
  position: absolute; bottom: 3px; transform: translateX(-50%);
  color: var(--rest); font-size: .65rem; font-weight: 600;
  white-space: nowrap; pointer-events: none;
}

.chart-axis { position: relative; height: 1.1rem; margin: .3rem 0 0 2.5rem; }
.ch-xlabel {
  position: absolute; transform: translateX(-50%);
  color: var(--text-2); font-size: .7rem; font-variant-numeric: tabular-nums;
}
.ch-xlabel-start { transform: none; }
.ch-xlabel-end { transform: translateX(-100%); }

/* Lit up when a length row is hovered — interaction chrome, not data, so it takes the
   interface accent rather than the series colour, and sits below the crosshair/dot. */
.ch-lap-highlight {
  position: absolute; top: 0; bottom: 0; background: var(--accent); opacity: .1;
  pointer-events: none;
}
.ch-crosshair {
  position: absolute; top: 0; bottom: 0; width: 1px;
  background: #4a5765; pointer-events: none;
}
.ch-dot {
  position: absolute; width: 9px; height: 9px; border-radius: 50%;
  background: var(--series); box-shadow: 0 0 0 2px var(--surface);
  transform: translate(-50%, -50%); pointer-events: none;
}
.ch-tip, .bar-tip {
  position: absolute; pointer-events: none; z-index: 2;
  background: var(--bg); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); padding: .25rem .5rem;
  font-size: .78rem; white-space: nowrap; transform: translate(-50%, -150%);
}
.ch-tip b, .bar-tip b { color: #fff; }

/* Trend bars are plain HTML: rounded ends and crisp text at any width. */
.trend-bars {
  position: relative; display: flex; align-items: flex-end; gap: 3px; height: 88px;
}
.bar { flex: 1; height: 100%; display: flex; align-items: flex-end; text-decoration: none; }
.bar-fill {
  width: 100%; height: var(--h); background: var(--series);
  border-radius: 4px 4px 0 0; transition: filter .12s ease;
}
.bar:hover .bar-fill, .bar:focus-visible .bar-fill { filter: brightness(1.35); }
.trend-axis {
  display: flex; justify-content: space-between;
  color: var(--text-2); font-size: .7rem; margin-top: .35rem;
}

/* ---------- activity calendar ---------- */

/* Rendered with a full 53 weeks, then JS trims from the oldest end to whatever actually fits —
   no scrollbar, and a narrow phone just sees fewer recent weeks rather than a clipped view. */
.cal-scroll { position: relative; overflow: hidden; padding-bottom: .2rem; }
.cal-grid { display: inline-flex; gap: 3px; }
/* Fixed to the cell's own width, not its content's — a label like "sept." is wider than 10px
   and would otherwise stretch this one column, breaking the uniform width fit() measures. It
   overflows into the empty label space of the following (unlabelled) columns instead, the way
   GitHub's own calendar does it. */
.cal-col { display: flex; flex-direction: column; gap: 3px; width: 10px; flex: none; }
/* Author `display: flex` above ties [hidden]'s specificity and would otherwise win over the
   browser's default [hidden] { display: none }, since author rules beat UA rules regardless of
   specificity — silently defeating fit()'s JS-driven column trimming. */
.cal-col[hidden] { display: none; }
.cal-month {
  height: 1rem; color: var(--text-2); font-size: .65rem; white-space: nowrap; overflow: visible;
}
.cal-days { display: flex; flex-direction: column; gap: 3px; }
.cal-cell { width: 10px; height: 10px; border-radius: 2px; background: var(--heat-0); }
.cal-cell.is-future { background: transparent; }
.cal-cell[data-level="1"] { background: var(--heat-1); }
.cal-cell[data-level="2"] { background: var(--heat-2); }
.cal-cell[data-level="3"] { background: var(--heat-3); }
.cal-cell[data-level="4"] { background: var(--heat-4); }
.cal-legend {
  display: flex; align-items: center; gap: .3rem; margin-top: .6rem;
  color: var(--text-2); font-size: .7rem;
}
.cal-legend .cal-cell { width: 10px; height: 10px; }
.cal-tip {
  position: absolute; pointer-events: none; z-index: 2;
  background: var(--bg); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); padding: .25rem .5rem;
  font-size: .78rem; white-space: nowrap; transform: translate(-50%, -130%);
}
/* Flipped for a top-row cell, where the usual above-the-cell placement would be clipped by
   .cal-scroll's own overflow:hidden. */
.cal-tip.cal-tip-below { transform: translate(-50%, 30%); }

/* ---------- month sections ---------- */

.month {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: 1.75rem 0 .6rem; padding-bottom: .4rem;
  border-bottom: 1px solid var(--border);
}
.month h2 { font-size: .9rem; margin: 0; font-weight: 600; letter-spacing: .01em; }
.month .month-total { color: var(--text-2); font-size: .8rem; }

/* ---------- swim card ---------- */

.swim {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .9rem 1rem; margin-bottom: .6rem;
  transition: border-color .12s ease;
}
.swim:hover { border-color: var(--border-strong); }
.swim > summary { cursor: pointer; list-style: none; }
.swim > summary::-webkit-details-marker { display: none; }
.swim > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--radius-sm); }

.swim-head { display: flex; align-items: center; gap: .75rem; }
.swim-headline {
  flex: 1; display: flex; align-items: baseline; justify-content: space-between;
  gap: .75rem; flex-wrap: wrap;
}
.dist { color: var(--accent); font-size: 1.3rem; font-weight: 700; letter-spacing: -.02em; }
.meta { color: var(--text-2); font-size: .85rem; }

/* Out of the way until select mode is on — most visits are read or delete-one, not merge. */
.pick { display: none; width: 1.05rem; height: 1.05rem; accent-color: var(--accent); cursor: pointer; flex: none; }
body.is-selecting .pick { display: block; }

.select-bar { display: flex; justify-content: flex-end; margin: -.3rem 0 .6rem; }
.share {
  color: var(--text-3); text-decoration: none; font-size: 1rem; line-height: 1;
  padding: .3rem; border-radius: var(--radius-sm); flex: none;
}
.share:hover { color: var(--accent); background: var(--surface-2); }

/* Set apart from the rest of the card's actions — reachable only once the swim is open, not
   sitting next to a link someone actually meant to click. */
.danger-zone { margin-top: 1rem; padding-top: .9rem; border-top: 1px solid var(--border); }
.delete-swim {
  color: var(--text-3); background: none; cursor: pointer; font: inherit; font-size: .85rem;
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: .4rem .8rem;
}
.delete-swim:hover { color: #e66767; border-color: #e66767; background: rgba(230, 103, 103, .08); }

.stats {
  display: flex; flex-wrap: wrap; gap: .45rem 1.4rem;
  margin: .9rem 0 .2rem; padding-top: .9rem;
  border-top: 1px solid var(--border); font-size: .88rem; color: var(--text-2);
}
.stats b { color: #fff; font-weight: 600; }

.provenance { color: var(--text-3); font-size: .8rem; margin: .5rem 0 0; }
.linkish {
  background: none; border: 0; padding: 0; font: inherit;
  color: var(--accent); cursor: pointer; text-decoration: underline;
}

.splits { margin-top: .9rem; }
.splits > summary {
  cursor: pointer; color: var(--text-2); font-size: .8rem;
  text-transform: uppercase; letter-spacing: .05em; list-style: none;
}
.splits > summary::-webkit-details-marker { display: none; }
.splits > summary::before { content: "▸ "; }
.splits[open] > summary::before { content: "▾ "; }
.splits .count { color: var(--text-3); }
.splits table { width: 100%; border-collapse: collapse; margin-top: .5rem; font-size: .88rem; }
.splits td { padding: .22rem 0; border-bottom: 1px solid var(--surface-2); }
.splits td.idx { color: var(--text-3); width: 2.2rem; }

/* Pace bar: length = speed, so it reads the same direction as the trend chart's bars — never
   a value ramp, just the one series colour at low opacity behind the time it belongs to. */
.splits td.pace { position: relative; }
.splits .pace-fill {
  position: absolute; left: 0; top: .28rem; bottom: .28rem; width: 0;
  background: var(--series); opacity: .16; border-radius: 3px;
}
.splits tr.is-best .pace-fill { opacity: .32; }
.splits .time {
  position: relative; display: block; text-align: right; padding-right: .5rem;
  font-variant-numeric: tabular-nums;
}
.splits tr.is-best .time { color: var(--accent); font-weight: 600; }

.splits td.hr {
  width: 4.6rem; padding-left: .6rem; text-align: right; color: var(--text-2);
  font-size: .82rem; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.splits td.hr .unit { color: var(--text-3); font-weight: 400; }

/* The row a hovered chart moment belongs to, and the length a hovered row highlights back on
   the chart (see .ch-lap-highlight) — the two views point at each other. */
.splits tr.is-hover td { background: var(--surface-2); }

/* ---------- merge action bar ---------- */

.merge-bar {
  position: fixed; left: 50%; bottom: 1rem; transform: translateX(-50%);
  display: flex; align-items: center; gap: .9rem;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: 999px; padding: .55rem .65rem .55rem 1.1rem;
  box-shadow: 0 .6rem 1.6rem rgba(0, 0, 0, .55); font-size: .88rem; z-index: 10;
}
.merge-bar[hidden] { display: none; }
.merge-bar button.go {
  background: var(--accent); color: var(--bg); border: 0; cursor: pointer;
  border-radius: 999px; padding: .4rem 1rem; font: inherit; font-weight: 600;
}
.merge-bar button.go:hover { filter: brightness(1.1); }

/* ---------- misc ---------- */

.empty { color: var(--text-2); }
.err { color: #e66767; font-size: .88rem; }

.account-row {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  padding: .7rem 0; border-bottom: 1px solid var(--border); font-size: .9rem;
}
.account-row span { flex: 1 1 auto; color: var(--text-2); }
.account-row b { color: var(--text); }
.pool-name-row input[type=text], .pool-name-row input[type=number] {
  font: inherit; color: var(--text); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm); padding: .35rem .5rem;
}
.pool-name-row input[type=text] { flex: 1 1 10rem; }
.pool-name-row input[type=number] { width: 5rem; }

.notice {
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm); padding: .6rem .9rem; margin-bottom: 1.25rem; font-size: .9rem;
}
.back { display: inline-block; margin-bottom: 1rem; font-size: .85rem; text-decoration: none; }

.login { max-width: 22rem; margin: 4rem auto; }
.login input[type=password] {
  width: 100%; padding: .6rem .8rem; font: inherit; color: var(--text);
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); margin: .6rem 0;
}
.login button {
  width: 100%; padding: .6rem; font: inherit; font-weight: 600; cursor: pointer;
  background: var(--accent); color: var(--bg); border: 0; border-radius: var(--radius-sm);
}
.login .err { color: #e66767; font-size: .88rem; }

@media (max-width: 34rem) {
  .ch-plot { height: 150px; }
  .dist { font-size: 1.15rem; }
  .stat-value { font-size: 1.3rem; }
  .swim-headline { gap: .2rem; }
}

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