/* Overview: the constellation fills the stage; the seal floats in front of it; planes sit over its edges. */

.ov {
  position: relative;
  display: grid;
  grid-template-columns: var(--rail) minmax(0, 1fr) calc(var(--rail-wide) + var(--float));
  grid-template-rows: minmax(440px, 1fr) auto;
  gap: var(--s4) var(--s5);
  min-height: 100%;
  padding: var(--s5) var(--gutter);
  overflow-x: clip;
}
.ov-field {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.ov-left,
.ov-right,
.hero,
.ov-time {
  position: relative;
  z-index: 1;
}
.ov-left {
  grid-column: 1;
  grid-row: 1 / 3;
  display: flex;
  flex-direction: column;
  gap: var(--s4);
}
.ov-right {
  grid-column: 3;
  grid-row: 1 / 3;
  display: flex;
  flex-direction: column;
  gap: var(--s4);
  min-height: 0;
}
.hero {
  grid-column: 2;
  grid-row: 1;
  min-height: var(--hero-min, 0px);
  --ring: 440px;
  --ring-top: 4px;
}
.ov-time {
  grid-column: 2;
  grid-row: 2;
}

/* ---------------------------------------------------------------- hero */
.hero-ring {
  position: absolute;
  left: 50%;
  top: var(--ring-top);
  width: var(--ring);
  height: var(--ring);
  margin-left: calc(var(--ring) / -2);
  pointer-events: none;
}
.hero-cap {
  position: absolute;
  left: 0;
  top: 0;
  display: grid;
  gap: var(--s1);
  max-width: 168px;
}
.hero-cap-main {
  font: 400 var(--t-small) / 1.4 var(--f-read);
  color: var(--ink-2);
}
.hero-cap-main .mono {
  font-size: var(--t-mini);
  color: var(--ink);
}
.hero-cap-sub {
  font-size: var(--t-mini);
  line-height: 1.45;
  color: var(--ink-3);
}
.hero-cap-sub .mono {
  color: var(--ink-2);
  font-size: var(--t-mini);
}
/* The map could not be read: said in gold where its caption would be, with a way to try again. */
.hero-cap-sub.is-warm {
  color: var(--gold);
}
.hero-cap-body {
  display: grid;
  gap: var(--s1);
  justify-items: start;
}
.hero-cap-body .btn {
  margin-top: var(--s1);
}
.hero-corner {
  position: absolute;
  right: 0;
  top: 0;
  display: grid;
  justify-items: end;
  text-align: right;
}
/* The link is a 40 px target; it is pulled up so its text lines up with the label opposite. */
.hero-open {
  min-height: 40px;
  margin-top: -13px;
}
.hero-corner .hero-cap-sub {
  margin-top: -7px;
}
.hero-lock {
  position: absolute;
  left: 50%;
  top: calc(var(--ring-top) + var(--ring) - 62px);
  width: 460px;
  margin-left: -230px;
}

/* Empty store: what to do first, inside the ring. */
/* A square block inside a circle: the title is centred where the circle is narrow, and the steps
   sit below it, where there is room for an address. */
.hero-empty {
  position: absolute;
  left: 50%;
  top: calc(var(--ring-top) + var(--ring) * 0.5);
  width: min(288px, calc(var(--ring) - 134px));
  transform: translate(-50%, -54%);
  display: grid;
  gap: var(--s3);
  justify-items: start;
}
.hero-empty-title {
  justify-self: center;
  font: 500 var(--t-head) / 1.2 var(--f-display);
  letter-spacing: 0.02em;
}
.hero-empty-sub,
.ov-start {
  display: none;
}
.steps {
  display: grid;
  gap: var(--s3);
  margin-top: var(--s1);
}
.step {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  gap: var(--s3);
  align-items: start;
}
.step-n {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: var(--hair) solid var(--line-3);
  font: 400 var(--t-mini)/1 var(--f-mono);
  color: var(--ink-2);
}
.step.is-done .step-n {
  border-color: var(--cyan);
  background: var(--cyan-fill-2);
  color: var(--cyan);
}
.step-title {
  font: 500 var(--t-ui) / 1.45 var(--f-display);
  letter-spacing: 0.02em;
}
.step-detail {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s3);
  font-size: var(--t-small);
  line-height: 1.4;
  color: var(--ink-3);
}
.step-detail .btn {
  margin: var(--s1) 0;
}
.addr {
  color: var(--ink-2);
  font-size: var(--t-mini);
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- store */
/* Spare height is shared out: the three planes grow together and their rows spread, so a tall
   window gets roomier readouts instead of a hole. */
.ov-left > .plane {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
}
.ov-left > .ov-store {
  flex-grow: 1.6;
}
.srcs,
.machine {
  flex: 1;
  align-content: space-between;
}
/* The plain words under each figure and a source for every app that saves take room the prototype
   did not need, so the rail's own spacing is a step tighter than elsewhere. */
.store-main {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  margin: var(--s1) 0 var(--s4);
}
.store-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s3);
  padding: var(--s3) 0;
  border-top: var(--hair) solid var(--line);
}
.ov-store .kv {
  margin-top: auto;
}
.ov-store .kv-row {
  min-height: 28px;
}
/* What each figure counts, in plain words under its label. */
.store-words {
  display: block;
  margin-top: 2px;
  font: 400 var(--t-mini) / 1.3 var(--f-read);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-3);
}
/* The last refresh failed: what is shown is older than the store. */
.ov-stale {
  color: var(--gold);
}

/* ---------------------------------------------------------------- sources */
.srcs-body {
  flex: 1;
  display: grid;
}
.srcs {
  display: grid;
  gap: var(--s2);
}
.srcs-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 44px;
  align-items: baseline;
  gap: var(--s1) var(--s3);
}
.srcs-count {
  font: 400 var(--t-small) / 1 var(--f-mono);
  color: var(--ink);
}
.srcs-share {
  font: 400 var(--t-mini)/1 var(--f-mono);
  color: var(--ink-3);
  text-align: right;
}
.srcs-row .meter {
  grid-column: 1 / -1;
}
.srcs-others {
  color: var(--ink-3);
}

/* ---------------------------------------------------------------- machine */
.machine {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s2);
}
.machine-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}
.machine-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  min-width: 0;
  min-height: 26px;
}
.machine-row.is-sub {
  min-height: 0;
  font-size: var(--t-mini);
  color: var(--ink-3);
}
.machine-row.is-sub .mono {
  font-size: var(--t-mini);
}
.machine-state {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font: 500 var(--t-ui) / 1 var(--f-display);
  letter-spacing: 0.02em;
}
.machine-state.is-warm {
  color: var(--gold);
}
/* The model's id can be long. Here it stays on one line; the system view has the whole of it. */
.machine-model {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.machine > .wait,
.machine > .fault {
  align-self: start;
}

/* ---------------------------------------------------------------- 90 days */
/* One column a day. Saved stands above the line and edited hangs below it, on one scale: `--split`
   is the share of the height above the line, `--up` and `--down` each bar's share of its side. */
.tl-legend {
  gap: var(--s2);
}
.tl-key {
  width: 7px;
  height: 7px;
  margin-left: var(--s2);
  background: var(--cyan);
}
.tl-key.is-edit {
  background: var(--cyan-2);
}
.tl-when {
  color: var(--ink-2);
}
.tl {
  --split: 0.667;
  --top: 18px;
  --foot: 22px;
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr);
  gap: var(--s2);
  height: 136px;
}
.tl-scale {
  position: relative;
  font: 400 var(--t-micro) / 1 var(--f-mono);
  color: var(--ink-3);
  text-align: right;
}
.tl-scale span {
  position: absolute;
  right: 0;
}
.tl-scale-top {
  top: calc(var(--top) - 4px);
}
.tl-scale-zero {
  top: calc(var(--top) + (100% - var(--top) - var(--foot)) * var(--split) - 5px);
}
.tl-scale-bot {
  bottom: calc(var(--foot) - 4px);
}
.tl-plot {
  position: relative;
  touch-action: pan-y;
}
.tl-bars {
  position: absolute;
  inset: var(--top) 0 var(--foot) 0;
  display: grid;
  grid-template-columns: repeat(90, minmax(0, 1fr));
  border-top: var(--hair) solid var(--line);
}
/* The line: saved above it, edited below. */
.tl-bars::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--split) * 100%);
  height: 1px;
  background: var(--line-3);
}
.tl-day {
  position: relative;
}
.tl-new,
.tl-edit {
  position: absolute;
  left: var(--hair);
  right: var(--hair);
  min-height: 2px;
}
.tl-new {
  bottom: calc((1 - var(--split)) * 100% + 1px);
  height: calc(var(--split) * var(--up) * 100% - 1px);
  background: var(--cyan);
}
.tl-edit {
  top: calc(var(--split) * 100% + 2px);
  height: calc((1 - var(--split)) * var(--down) * 100% - 2px);
  background: var(--cyan-2);
}
/* The day being pointed at, or reached with the arrow keys. */
.tl-day.is-cursor {
  background: var(--cyan-fill-2);
}
/* The busiest day: a hairline from its bar up to its note. */
.tl-day.is-peak::before {
  content: "";
  position: absolute;
  left: 50%;
  top: calc(var(--top) * -1);
  width: 1px;
  height: calc(var(--top) + var(--split) * (1 - var(--up)) * 100% - 2px);
  background: var(--ink-3);
}
.tl-call {
  position: absolute;
  top: 0;
  left: var(--x);
  padding: 0 0 0 6px;
  font: 400 var(--t-micro) / 12px var(--f-mono);
  color: var(--ink-3);
  white-space: nowrap;
  pointer-events: none;
}
.tl-call.is-left {
  padding: 0 6px 0 0;
  transform: translateX(-100%);
}
.tl-call b {
  font-weight: 400;
  color: var(--ink);
}
.tl-none {
  position: absolute;
  left: var(--s2);
  right: var(--s2);
  top: calc(var(--top) + var(--s2));
  font-size: var(--t-small);
  color: var(--ink-3);
}
.tl-axis {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--foot);
  border-top: var(--hair) solid var(--line);
  container-type: inline-size;
}
.tl-tick {
  position: absolute;
  top: 0;
  width: 1px;
  height: 4px;
  background: var(--line-2);
}
.tl-tick.is-month {
  height: 8px;
  background: var(--ink-3);
}
.tl-month {
  position: absolute;
  top: 11px;
  left: 0;
  transform: translateX(-50%);
  font: 400 var(--t-micro) / 1 var(--f-mono);
  color: var(--ink-3);
  white-space: nowrap;
}
.tl-tick.is-today .tl-month {
  transform: translateX(-100%);
  left: 3px;
  color: var(--ink-2);
}
/* On a narrow chart (a phone) a month that began in the last few days would be written over
   "today": its tick stays, its name gives way. */
@container (max-width: 520px) {
  .tl-tick.is-late .tl-month {
    display: none;
  }
}

/* ---------------------------------------------------------------- activity */
.ov-activity-wrap {
  flex: 1;
}
.ov-activity {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* The list scrolls inside its plane, which takes the height that is left: however many rows it
   holds, they never make the page taller (`contain: size`). It reaches the plane's edges, so the
   mark beside a refused call is not cut off. */
.acts-box {
  flex: 1 1 auto;
  min-height: 190px;
  contain: size;
  margin: 0 calc(var(--s4) * -1);
  padding: 0 var(--s4);
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.acts-box:focus-visible {
  outline-offset: -2px;
}
.acts {
  display: grid;
}
.act {
  position: relative;
  display: grid;
  grid-template-columns: 62px 78px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s2);
  min-height: 38px;
  border-top: var(--hair) solid var(--line);
  font-size: var(--t-small);
}
.act:first-child {
  border-top: 0;
}
.act-time {
  font: 400 var(--t-mini)/1 var(--f-mono);
  color: var(--ink-3);
}
.act-actor {
  /* Room for the descenders ("Lock page"), which the cut would otherwise clip. */
  font: 500 var(--t-small) / 1.3 var(--f-display);
  letter-spacing: 0.02em;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.act-what {
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.act-detail {
  font: 400 var(--t-mini) var(--f-mono);
  color: var(--ink-3);
}
.act-out {
  font: 400 var(--t-mini)/1 var(--f-mono);
  color: var(--ink-3);
  text-align: right;
  white-space: nowrap;
}
.act.is-refused::before {
  content: "";
  position: absolute;
  left: calc(var(--s4) * -1);
  top: 9px;
  bottom: 9px;
  width: var(--bold);
  background: var(--gold);
}
.act.is-fresh {
  animation: act-arrive 320ms var(--ease-out);
}
/* Empty slots stay ruled: the log is waiting, not missing. */
.act.is-blank::after {
  content: "";
  grid-column: 1 / -1;
  height: 1px;
}
.act.is-blank:last-child {
  border-bottom: var(--hair) solid var(--line);
}
.act-more {
  display: flex;
  justify-content: center;
  padding: var(--s1) 0;
  border-top: var(--hair) solid var(--line);
}
.act-fault {
  padding: var(--s3) 0;
}
.plane-readout.is-warm {
  color: var(--gold);
}
.news.is-blank .news-row {
  min-height: 36px;
}
.news-empty {
  display: grid;
  gap: var(--s3);
  justify-items: start;
  padding-top: var(--s1);
  border-top: var(--hair) solid var(--line);
}
@keyframes act-arrive {
  from {
    opacity: 0;
    transform: scale(0.94);
  }
}
/* The poll hand: turns one step each time the page asks the server for its pulse. */
.pulse {
  position: relative;
  width: 12px;
  height: 12px;
  border: var(--hair) solid var(--line-3);
  border-radius: 50%;
}
.pulse-hand {
  position: absolute;
  left: 5px;
  top: -1px;
  width: 0;
  height: 6px;
  border-left: var(--hair) solid var(--cyan);
  transform-origin: 0 6px;
  transition: transform 400ms var(--ease-out);
}

/* ---------------------------------------------------------------- newest */
.news-row {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  gap: var(--s1) var(--s2);
  align-content: center;
  min-height: 50px;
  padding: var(--s1) 0;
  border-top: var(--hair) solid var(--line);
  text-decoration: none;
}
li:first-child > .news-row {
  border-top: 0;
}
.news-n {
  grid-row: 1 / 3;
  align-self: start;
  padding-top: var(--s1);
  font: 400 var(--t-micro) / 1 var(--f-mono);
  color: var(--ink-3);
}
.news-title {
  font: 400 var(--t-ui) / 1.3 var(--f-read);
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.news-meta {
  display: flex;
  align-items: center;
  gap: var(--s3);
  font: 400 var(--t-mini)/1 var(--f-mono);
  color: var(--ink-3);
}
.news-meta .src {
  font-size: var(--t-mini);
  color: var(--ink-3);
}
.news-age {
  flex: none;
}
.news-row:hover .news-title {
  color: var(--cyan);
}
.news-row:hover .news-n {
  color: var(--ink);
}
.news-row:focus-visible {
  outline-offset: -2px;
}

/* ---------------------------------------------------------------- medium widths */
@media (max-width: 1240px) and (min-width: 1041px) {
  .ov {
    grid-template-columns: minmax(0, 1fr) calc(340px + var(--float));
    grid-template-rows: 560px auto auto;
  }
  .hero {
    grid-column: 1;
    grid-row: 1;
  }
  .ov-time {
    grid-column: 1;
    grid-row: 2;
  }
  .ov-right {
    grid-column: 2;
    grid-row: 1 / 3;
  }
  .ov-left {
    grid-column: 1 / 3;
    grid-row: 3;
    flex-direction: row;
  }
  .ov-left > .plane {
    flex: 1;
  }
}

/* ---------------------------------------------------------------- phone */
@media (max-width: 1040px) {
  .ov {
    display: flex;
    flex-direction: column;
    gap: var(--s4);
    padding: var(--s4) var(--gutter) var(--s5);
  }
  .ov-left,
  .ov-right {
    display: contents;
  }
  .ov-field {
    inset: 0 0 auto 0;
    height: 620px;
  }
  .hero {
    order: 0;
    flex: none;
    height: calc(100vw - 2 * var(--gutter) + 150px);
    --ring-top: 44px;
  }
  .hero-cap {
    max-width: 66%;
  }
  /* Empty store on a phone: the ring holds one sentence; the steps follow it as a plane. */
  .hero-empty {
    width: calc(var(--ring) - 120px);
    transform: translate(-50%, -50%);
    justify-items: center;
    text-align: center;
  }
  .hero-empty .steps,
  .ov.is-empty .hero-cap .hero-cap-sub {
    display: none;
  }
  .hero-empty-sub {
    display: block;
    font-size: var(--t-small);
    color: var(--ink-3);
  }
  .ov-start {
    display: block;
    order: 0;
  }
  .hero-corner .hero-cap-sub {
    display: none;
  }
  .hero-lock {
    width: 100%;
    left: 0;
    margin-left: 0;
  }
  .ov-left > .plane {
    flex: none;
  }
  .ov-store {
    order: 1;
  }
  .acts-box {
    flex: none;
    min-height: 0;
    contain: none;
    overflow: visible;
  }
  .ov-activity-wrap {
    order: 2;
    flex: none;
  }
  .ov-time {
    order: 3;
  }
  .ov-newest-wrap {
    order: 4;
  }
  .ov-sources {
    order: 5;
  }
  .ov-machine {
    order: 6;
  }
  .ov-time .plane-head {
    flex-wrap: wrap;
    row-gap: var(--s2);
  }
  .store-main {
    margin-bottom: var(--s4);
  }
  .ov-store .kv {
    margin-top: 0;
  }
  .act {
    grid-template-columns: 58px 72px minmax(0, 1fr) auto;
    min-height: 40px;
  }
  .tl {
    height: 124px;
  }
}

/* ---------------------------------------------------------------- between phone and desktop: planes two abreast */
@media (min-width: 761px) and (max-width: 1040px) {
  .ov {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
  }
  .ov-field {
    height: 700px;
  }
  .hero,
  .ov-time,
  .ov-newest-wrap,
  .ov-start {
    grid-column: 1 / -1;
  }
  .hero {
    height: 640px;
    --ring-top: 8px;
  }
  .hero-lock {
    width: 460px;
    left: 50%;
    margin-left: -230px;
  }
  .hero-corner .hero-cap-sub {
    display: block;
  }
  .ov-sources {
    order: 4;
  }
  .ov-machine {
    order: 5;
  }
  .ov-newest-wrap {
    order: 6;
  }
  .ov-left > .plane,
  .ov-activity-wrap {
    align-self: stretch;
  }
}

