:root {
  --bg: #0b0d0e;
  --panel: #121618;
  --line: #1f272a;
  --fg: #d7e0e2;
  --dim: #6b7b80;
  --accent: #34e2ea;
  --accent2: #ffa657;
  --win: #6ee787;
  --lose: #ff7b72;
  --mono: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background:
    radial-gradient(900px 500px at 50% -10%, #12303380, transparent 70%),
    var(--bg);
  color: var(--fg);
  font-family: var(--mono);
  font-size: 15px;
  line-height: 1.6;
  min-height: 100vh;
  display: flex;
  justify-content: center;
}

main {
  width: 100%;
  max-width: 820px;
  padding: 3rem 1.25rem 2rem;
}

header { margin-bottom: 2rem; }

h1 {
  font-size: clamp(1.5rem, 6vw, 2.4rem);
  letter-spacing: 0.1em;
  margin: 0 0 0.4rem;
  color: var(--accent);
  overflow-wrap: anywhere;
}

.dim { color: var(--line); }

.tagline { margin: 0; color: var(--dim); }
.tagline strong { color: var(--fg); font-weight: 600; }

section { margin-top: 2.6rem; }

.section-heading {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--dim);
  font-weight: 400;
  margin: 0 0 0.9rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--line);
}

.fine {
  font-size: 0.85rem;
  color: var(--dim);
  border-left: 2px solid var(--line);
  padding-left: 0.9rem;
  margin: 0.9rem 0;
}

.status { color: var(--dim); }
.status.error {
  color: var(--lose);
  border-left: 2px solid var(--lose);
  padding-left: 0.9rem;
}

/* --- counters ---------------------------------------------------------- */

.counters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: 0.7rem;
}

.counter {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0.8rem 0.9rem;
  min-width: 0;
}
.counter-value {
  font-size: clamp(1.5rem, 6vw, 2rem);
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.counter-label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--dim);
}
.counter-sub { font-size: 0.78rem; color: var(--dim); }

/* --- time-lapse -------------------------------------------------------- */

.tl-frame {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0.9rem;
}

.tl-readout {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.1rem;
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  color: var(--dim);
  margin-bottom: 0.55rem;
}
.tl-date { color: var(--fg); min-width: 8.5rem; }
.tl-repos { color: var(--accent); }
.tl-agents { color: var(--accent2); }

/* aspect-ratio rather than a fixed height, so the dot field keeps its shape at
   360px instead of squashing into a band. display:block kills the inline
   baseline gap under the canvas. */
#tl-canvas {
  display: block;
  width: 100%;
  max-width: 100%;
  aspect-ratio: 8 / 5;
  background: #0d1113;
  border: 1px solid var(--line);
  border-radius: 3px;
}

.tl-progress {
  height: 4px;
  margin-top: 0.55rem;
  background: #161c1e;
  border-radius: 2px;
  overflow: hidden;
}
.tl-progress-fill { display: block; height: 100%; width: 0; background: var(--accent); }

.tl-controls { display: flex; gap: 0.5rem; margin-top: 0.7rem; }

.tl-button {
  font-family: inherit;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg);
  background: #161c1e;
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 0.35rem 0.9rem;
  cursor: pointer;
  min-width: 5.5rem;
}
.tl-button:hover { border-color: var(--accent); color: var(--accent); }
.tl-button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* flex-wrap and no fixed width, so three buttons stack instead of pushing the
   panel sideways at 360px. */
.tl-controls { flex-wrap: wrap; }

/* --- live mode --------------------------------------------------------- */

.tl-live {
  margin-top: 0.9rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
}

.tl-live-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 0.7rem;
}

/* The chip states carry their own word as well as their own colour, so the
   difference between live and not connected survives greyscale. */
.tl-live-state {
  flex: none;
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 0.1rem 0.45rem;
  color: var(--dim);
}
.tl-live-state.up { color: var(--win); border-color: #23502f; }
.tl-live-state.down { color: var(--lose); border-color: #5a2a26; }

/* The one line that answers "is this working". Sized up because the whole
   panel is usually reporting that nothing has happened, and that sentence is
   the content rather than the caveat. */
.tl-live-headline {
  font-size: 1.05rem;
  color: var(--fg);
  overflow-wrap: anywhere;
}
.tl-live-state.down + .tl-live-headline { color: var(--lose); }

.tl-live-sub {
  margin: 0.25rem 0 0;
  font-size: 0.78rem;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.tl-live-sub:empty { display: none; }

.tl-live-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.6rem;
  margin-top: 0.7rem;
}
.tl-live-cell { display: flex; flex-direction: column; min-width: 0; }
.tl-live-value {
  font-size: 1.1rem;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
}
.tl-live-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--dim);
}
.tl-live-delta { font-size: 0.72rem; color: var(--accent2); }

.tl-live-note {
  margin: 0.7rem 0 0;
  font-size: 0.8rem;
  color: var(--dim);
  border-left: 2px solid var(--line);
  padding-left: 0.8rem;
}
.tl-live-note:empty { display: none; }

.tl-live-feed { display: flex; flex-direction: column; margin-top: 0.7rem; }
.tl-live-row {
  display: grid;
  grid-template-columns: 3.2rem minmax(0, 1fr);
  gap: 0.1rem 0.6rem;
  padding: 0.35rem 0;
  border-top: 1px solid #161c1e;
  font-size: 0.82rem;
}
.tl-live-kind {
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 0.05rem 0.25rem;
  text-align: center;
  color: var(--accent2);
  align-self: start;
}
.tl-live-kind.new { color: var(--accent); border-color: #1d4a4d; }
.tl-live-name { overflow-wrap: anywhere; }
.tl-live-meta { grid-column: 2; font-size: 0.74rem; color: var(--dim); overflow-wrap: anywhere; }
.tl-live-empty { margin: 0; font-size: 0.8rem; color: var(--dim); }

/* --- chart ------------------------------------------------------------- */

.chart-frame {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0.9rem;
}

.chart-head, .chart-axis {
  display: flex;
  justify-content: space-between;
  gap: 0.6rem;
  font-size: 0.74rem;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.chart-head { margin-bottom: 0.35rem; }
.chart-axis { margin-top: 0.35rem; }

/* height:auto keeps the aspect ratio from the viewBox, so the curve shrinks
   with the viewport instead of forcing the page sideways at 360px. */
/* Direct child only. As a descendant selector this also caught the legend
   swatches, which stretched to the full column width and shoved their labels
   off the right edge at 360px. */
.chart-frame > svg { display: block; width: 100%; height: auto; }

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: 0.8rem;
  font-size: 0.8rem;
  color: var(--dim);
}
.legend-item { display: flex; align-items: center; gap: 0.45rem; }
.legend-swatch { flex: none; width: 34px; height: 10px; }

.chart-caption { margin: 0.9rem 0 0; font-size: 0.85rem; color: var(--dim); }
.chart-caption strong { color: var(--fg); font-weight: 600; }

/* --- punchcard --------------------------------------------------------- */

/* minmax(0, 1fr) on the 24 hour columns, not auto: fractional columns divide
   whatever width is there, so the grid shrinks to 360px instead of pushing the
   page sideways. The gutter is in ch so it tracks the three-character day
   labels in the monospace face. */
.pc-grid, .pc-axis, .pc-totals {
  display: grid;
  grid-template-columns: 3.4ch repeat(24, minmax(0, 1fr));
  gap: 2px;
  align-items: center;
}

.pc-day {
  font-size: 0.62rem;
  color: var(--dim);
  letter-spacing: 0.02em;
  text-align: right;
  padding-right: 0.3rem;
}

/* Square cells that follow the column width, so the whole card keeps its
   proportions from 360px up to the 820px column. */
.pc-cell {
  aspect-ratio: 1;
  min-width: 0;
  background: #161c1e;
  border-radius: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Size and opacity both carry the count, set inline from the derived intensity.
   Printed or in greyscale the opacity flattens towards the cell background and
   the side length is what still reads. */
.pc-dot {
  display: block;
  background: var(--accent);
  border-radius: 1px;
}
/* A slot with nothing in it is not a very small amount of something, so it gets
   no mark at all rather than the smallest one. */
.pc-dot.empty { background: none; }

.pc-axis { margin-top: 3px; }

/* The column sums under the lattice. Fixed height rather than aspect-ratio,
   since these are bars and not squares, and they carry the swing the grid
   itself is too flat to show. */
.pc-totals { margin-top: 5px; align-items: end; }
.pc-bar {
  height: 26px;
  min-width: 0;
  background: #161c1e;
  border-radius: 2px;
  display: flex;
  align-items: flex-end;
}
.pc-bar-fill {
  display: block;
  width: 100%;
  background: var(--accent);
  opacity: 0.55;
  border-radius: 2px;
  min-height: 1px;
}
.pc-bar-fill.peak { opacity: 1; }
.pc-tick {
  font-size: 0.62rem;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
  text-align: center;
  /* The label is wider than its 9px column at 360px, so it is allowed to spill
     symmetrically over its neighbours instead of wrapping to two lines. */
  overflow: visible;
  white-space: nowrap;
}

.pc-scale {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.9rem;
  font-size: 0.72rem;
  color: var(--dim);
}
.pc-ramp { display: flex; gap: 2px; }
.pc-ramp .pc-cell { width: 14px; }

/* --- proportional rows (owners, capabilities) -------------------------- */

.rows { display: flex; flex-direction: column; gap: 0.35rem; }

.row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.2rem 0.8rem;
  align-items: baseline;
}
.row-label { font-size: 0.85rem; overflow-wrap: anywhere; }
.row-count { font-size: 0.85rem; color: var(--dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.row-bar {
  grid-column: 1 / -1;
  height: 5px;
  background: #161c1e;
  border-radius: 2px;
  overflow: hidden;
}
.row-bar-fill { height: 100%; background: var(--accent); display: block; }
.row-bar-fill.alt { background: var(--accent2); }

/* --- footer ------------------------------------------------------------ */

footer {
  margin-top: 3rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--line);
  color: var(--dim);
  font-size: 0.82rem;
}
a { color: var(--dim); text-decoration: underline; text-underline-offset: 2px; }
a:hover { color: var(--accent); }

@media (max-width: 420px) {
  main { padding: 2rem 0.9rem 2rem; }
}
