/* Every value here comes from tokens.css. No literals. */

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 16px/1.5 var(--face-ui);
}

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

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

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

.masthead {
  display: flex;
  align-items: baseline;
  gap: var(--s4);
  flex-wrap: wrap;
  padding: var(--s1) var(--s3);
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
}

.masthead__name {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding-right: var(--s2);
  font-family: var(--face-call);
  font-size: 18px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--accent);
  text-decoration: none;
}

.masthead__tally {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s4);
  margin: 0;
  font-size: 14px;
  color: var(--ink-muted);
}

/* On a phone the wall is what the screen is for, so the header packs tight and
   only spreads out when there is width to spare. */
.masthead__spacer { display: none; }

@media (min-width: 700px) {
  .masthead__spacer { display: block; margin-left: auto; }
}

.masthead__tally b {
  font-family: var(--face-call);
  font-weight: 500;
  color: var(--ink);
}

main { padding: var(--s2) var(--s3); }

/* The wall page is the viewport and nothing more. Locking it here is what keeps
   the whole shelf countable without scrolling; anything that needs more room
   than it has scrolls inside its own box rather than pushing the wall down. */
.fills { height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
.fills main { flex: 1 1 auto; min-height: 0; overflow: hidden; }
.fills .room { height: 100%; }
.fills .side { overflow-y: auto; }

/* ---- the wall ---------------------------------------------------------- */

/* The whole shelf, visible at once. A cell is the viewport divided by the
   tallest column, so eleven columns of the same height stay the same height and
   nothing needs scrolling to be counted. Below --cell-min it stops shrinking and
   the page scrolls instead: a row too small to read is worse than a scrollbar. */
.wall {
  --cell-h: max(var(--cell-min), calc((100dvh - var(--wall-chrome)) / var(--rows, 28)));
  display: flex;
  gap: var(--s1);
  align-items: flex-start;
  overflow-x: auto;
}

.column {
  /* min-width: 0, or a flex item grows to fit its content and one column ends
     up wider than the rest of the same shelving. */
  flex: 0 0 var(--col-w);
  min-width: 0;
  max-width: var(--col-w);
  border: 1px solid var(--rule);
  background: var(--paper-sunk);
}

.column__head {
  display: flex;
  flex-wrap: nowrap;
  align-items: baseline;
  gap: var(--s1);
  padding: var(--s1) var(--s2);
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
}

.column__label {
  font-family: var(--face-call);
  font-size: 15px;
  font-weight: 500;
}

/* One line, always. A column that holds four numbers would otherwise wrap its
   header and stand taller than its neighbours, which hold the same cells. */
.column__numbers {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 11px;
  color: var(--ink-muted);
}



/* ---- a shelf ----------------------------------------------------------- */

/* The callsign sits in the bottom cell, centred in it -- not centred in the
   whole shelf. A seven-deep shelf is one plate with air above it, and the label
   on the wall is on the plate, so that is where the eye looks for it. */
.shelf {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  width: 100%;
  /* Exactly its height, never rounded. Every column holds the same number of
     cells, so any fudge here makes two columns that are the same height in the
     room different heights on the screen. One cell is --cell-h and --cell-h is
     the thumb, so the target is met without bending the scale. */
  height: calc(var(--cell-h) * var(--cells, 1));
  align-items: center;
  padding: 0 var(--s2);
  overflow: hidden;
  border: 0;
  border-bottom: 2px solid var(--plate);  /* the plate itself */
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.shelf__call {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Exactly one cell tall, pinned to the bottom of the shelf, so the callsign
     is centred in the plate's own cell whatever the height above it. */
  height: var(--cell-h);
  font-family: var(--face-call);
  /* Shrinks with the cell, but never below readable. */
  font-size: clamp(10px, calc(var(--cell-h) * 0.42), 15px);
  font-weight: 500;
  line-height: 1;
}

.shelf__name {
  font-size: 12px;
  color: var(--ink-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.shelf--cards { background: var(--state-cards); color: var(--ink-on-cards); }
.shelf--cards .shelf__name { color: var(--ink-on-cards); }

/* Full is the loudest thing on the screen, and says so without relying on hue. */
/* No extra rule down the side. It was there as a cue that did not depend on
   hue, but the three states are already 83, 33 and 8 percent light, which is
   separation enough to survive greyscale -- and a bar in the strong ink reads
   as a broken edge rather than a mark. */
.shelf--full {
  background: var(--state-full);
  color: var(--ink-on-full);
}

.shelf:active {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

.shelf[data-pending="1"] { opacity: 0.55; }

/* ---- the guest pile ---------------------------------------------------- */

.pile {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  /* Sits on the floor of the column, where the pile actually is. */
  padding-bottom: var(--s2);
  /* No vertical padding: a column whose pile is nought cells must collapse to
     nothing, and padding is a floor the height cannot go under. */
  padding: 0 var(--s2);
  margin: 0;
  overflow: hidden;
  border-top: 1px dashed var(--rule);
  color: var(--ink-muted);
  font-size: 12px;
  text-align: center;
}

/* ---- states the screen has to be able to be ---------------------------- */

.notice {
  max-width: 60ch;
  margin: var(--s6) auto;
  padding: var(--s4);
  border: 1px solid var(--rule);
  background: var(--paper-sunk);
}

.notice h2 { margin: 0 0 var(--s2); font-size: 20px; }
.notice p  { margin: 0 0 var(--s3); }

.offline {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: var(--s2) var(--s4);
  border-bottom: 1px solid var(--rule-strong);
  background: var(--state-cards);
  color: var(--ink-on-cards);
  font-size: 14px;
}

.offline[hidden] { display: none; }

/* ---- login ------------------------------------------------------------- */

.signin { max-width: 22rem; margin: var(--s7) auto; padding: 0 var(--s4); }
.signin h1 { font-size: 28px; margin: 0 0 var(--s5); }
.signin label { display: block; margin-bottom: var(--s1); font-size: 14px; font-weight: 500; }

.signin input {
  width: 100%;
  min-height: var(--tap);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  font: 400 16px/1.5 var(--face-ui);   /* never below 16px, or iOS zooms */
  margin-bottom: var(--s4);
}

/* Anchors and buttons both, so a link that acts like a button lays out like
   one instead of running into its neighbour. */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  text-decoration: none;
  min-height: var(--tap);
  padding: var(--s2) var(--s5);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--paper);
  font: 500 16px/1.5 var(--face-ui);
  cursor: pointer;
}

.button:active { background: var(--accent-press); border-color: var(--accent-press); }

.error {
  padding: var(--s2) var(--s3);
  border-left: 4px solid var(--state-full);
  background: var(--paper-sunk);
  margin-bottom: var(--s4);
}

.masthead__nav {
  display: flex;
  align-items: center;
  gap: var(--s2);
}

.linklike {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  border: 0;
  background: none;
  padding: var(--s2);
  min-height: var(--tap);
  color: var(--accent);
  font: 400 14px/1.5 var(--face-ui);
  cursor: pointer;
}
.linklike:active { color: var(--accent-press); }

/* ---- a cell: the shelf, and the way into what else the person holds ------ */

.cell {
  position: relative;
  height: calc(var(--cell-h) * var(--cells, 1));
}

.cell .shelf { height: 100%; }

.more {
  position: absolute;
  top: 0;
  right: 0;
  width: 22px;
  height: 100%;
  border: 0;
  border-left: 1px solid var(--rule);
  background: transparent;
  color: inherit;
  font: 500 15px/1 var(--face-call);
  cursor: pointer;
}

.more:active { background: var(--paper-sunk); }
.more[aria-expanded="true"] { background: var(--rule-strong); color: var(--paper); }

/* Overlays rather than pushes: every column holds the same number of cells and
   has to stay the same height whatever is open. */
.extra {
  position: absolute;
  top: 100%;
  /* Anchored left, not right: the wall is a horizontal scroll container, so a
     panel hanging off the left of the first column gets clipped away. */
  left: 0;
  z-index: 3;
  min-width: 11rem;
  max-width: 16rem;
  padding: var(--s3);
  border: 1px solid var(--rule-strong);
  background: var(--paper);
  color: var(--ink);
}

.extra__who { margin: 0 0 var(--s2); font-size: 14px; font-weight: 500; }
.extra__list { margin: 0; padding: 0; list-style: none; }
.extra__list li { display: flex; justify-content: space-between; gap: var(--s3); padding: var(--s1) 0; }
.extra__call { font-family: var(--face-call); font-size: 14px; }
.extra__kind { font-size: 12px; color: var(--ink-muted); }

.cell[data-pending="1"] .shelf { opacity: 0.55; }


/* ---- the room: wall on the left, what you do about it on the right ------ */

.room {
  display: flex;
  gap: var(--s3);
  align-items: flex-start;
}

.wall { flex: 1 1 auto; min-width: 0; }

.side {
  flex: 0 0 15rem;
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.side__block {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--s2);
  padding: var(--s3);
  border: 1px solid var(--rule);
  background: var(--paper-sunk);
}

.side__block h2 { margin: 0; font-size: 16px; }
.side__block p { margin: 0; font-size: 14px; }
.side__block label { margin: 0; font-size: 14px; font-weight: 500; }
.side__count b { font-family: var(--face-call); font-size: 20px; }

.side input[type="search"], .panel input[type="text"] {
  width: 100%;
  min-height: var(--tap);
  padding: var(--s2);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  font: 500 16px/1.2 var(--face-call);
  text-transform: uppercase;
}

/* ---- what to do with the card in your hand ----------------------------- */

.answer--none { display: none; }

.answer {
  margin-top: var(--s2);
  padding: var(--s2) var(--s3);
  border-left: 4px solid var(--rule);
  background: var(--paper);
}

.answer__call { margin: 0; font: 500 18px/1.2 var(--face-call); }
.answer__says { margin: var(--s1) 0 0; font-size: 14px; }
.answer__where { margin: var(--s1) 0 0; font: 400 13px/1.2 var(--face-call); color: var(--ink-muted); }

.answer--on_shelf { border-left-color: var(--accent); }
.answer--other_call { border-left-color: var(--accent); }
.answer--guest { border-left-color: var(--state-cards); }
.answer--member_no_shelf { border-left-color: var(--state-cards); }
.answer--unknown { border-left-color: var(--state-full); }

/* The wall is three hundred cells; words alone will not find one of them. Green
   because it is the only colour on this interface that means nothing else --
   amber and rust are states a shelf can be in, and a search must not look like
   one. */
@keyframes wave {
  0%, 100% { background: var(--found); }
  50%      { background: transparent; }
}

.cell--flash .shelf {
  animation: wave 0.5s steps(1) 6;
  outline: 3px solid var(--found);
  outline-offset: -3px;
}

.cell--flash .shelf__call { color: var(--ink); }

/* ---- putting shelves in and taking them out ---------------------------- */

.panel {
  padding: var(--s3);
  border: 1px solid var(--rule);
  background: var(--paper-sunk);
}

.panel__form + .panel__form { margin-top: var(--s4); }
.panel__form label { display: block; margin-bottom: var(--s1); font-size: 14px; font-weight: 500; }
.panel__row { display: flex; gap: var(--s1); margin-top: var(--s1); }
.panel__row .button { flex: 1 1 0; }

.panel__problem {
  margin: 0 0 var(--s3);
  padding: var(--s2) var(--s3);
  border-left: 4px solid var(--state-full);
  background: var(--paper);
  font-size: 14px;
}

.panel__job { margin-bottom: var(--s4); padding-bottom: var(--s3); border-bottom: 1px solid var(--rule); }
.panel__job h2 { margin: 0 0 var(--s1); font-size: 16px; }
.panel__call { margin: 0 0 var(--s1); font: 500 20px/1.2 var(--face-call); }
.panel__todo { margin: var(--s2) 0; padding-left: 1.2em; font-size: 14px; }
.panel__todo li { margin-bottom: var(--s1); }

.button--quiet {
  background: var(--paper);
  color: var(--accent);
  border-color: var(--rule);
}
.button--quiet:active { background: var(--paper-sunk); }

/* ---- legend ------------------------------------------------------------ */

.legend {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s1) var(--s2);
  align-items: center;
  margin: 0;
  padding: var(--s3);
  border: 1px solid var(--rule);
}

.legend dt { margin: 0; }
.legend dd { margin: 0; font-size: 14px; }

.swatch {
  display: block;
  width: 22px;
  height: 16px;
  border: 1px solid var(--rule-strong);
}

.swatch--empty { background: var(--paper); }
.swatch--cards { background: var(--state-cards); }
.swatch--full  { background: var(--state-full); }

/* ---- what a round of checking wrote down ------------------------------- */

.sheet { max-width: 48rem; margin: 0 auto; padding: var(--s5) var(--s4); }
.sheet h1 { margin: 0 0 var(--s4); font-size: 28px; }
.sheet h2 { margin: var(--s6) 0 var(--s2); font-size: 20px; }
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th, .table td { padding: var(--s2); border-bottom: 1px solid var(--rule); text-align: left; }
.table th { font-size: 13px; font-weight: 500; }
.mono { font-family: var(--face-call); }
.soon { color: var(--ink-muted); }

/* ---- on a phone ---------------------------------------------------------
   The wall does not fit a phone screen and pretending otherwise is what broke
   it: the page was locked to the viewport, so the side panel scrolled and the
   wall underneath could never be reached past it. On a narrow screen the page
   simply scrolls, the wall comes first because it is what the page is for, and
   a cell goes back to a size a thumb can hit. */
@media (max-width: 900px) {
  .fills { height: auto; display: block; overflow: visible; }
  .fills main { overflow: visible; }
  .fills .room { height: auto; }
  .fills .side { overflow: visible; }

  /* stretch, not flex-start: in a column the cross axis is the width, and
     flex-start let the wall size itself to its own content -- 1340px of it --
     so the page scrolled sideways instead of the wall scrolling inside it. */
  .room { flex-direction: column; align-items: stretch; }
  .side { flex: 1 1 auto; width: 100%; }
  .wall { width: 100%; }

  .wall { --cell-h: 44px; }

  .masthead { padding: var(--s1) var(--s2); }
  .masthead__tally { font-size: 13px; }

  /* Wide content scrolls in its own box rather than pushing the page sideways. */
  .sheet { padding: var(--s3) var(--s2); }
  .table { display: block; overflow-x: auto; white-space: nowrap; }
}

/* ---- what has to be carried -------------------------------------------- */

.column__cells { position: relative; }

/* Drawn over the cells the job covers. The rows already say what they will
   say; this is the instruction to whoever is doing the lifting. */
.carry {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  pointer-events: none;
}

.carry__arrow {
  font: 500 28px/1 var(--face-ui);
  color: var(--paper);
  background: var(--accent);
  border-radius: 50%;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* A shelf that has just been put in stays green until it is called done. */
.cell--new .shelf {
  background: #1d7a3d;
  color: var(--paper);
  box-shadow: inset 0 0 0 2px var(--rule-strong);
}

.cell--new .shelf__call { color: var(--paper); }

/* Takes its colour from the wordmark it sits beside, so it holds up in both
   themes without a second file to keep in step. */
.masthead__mark {
  width: 26px;
  height: 26px;
  margin-right: var(--s2);
  flex: 0 0 auto;
}

.panel__where {
  margin: 0 0 var(--s2);
  font: 500 14px/1.2 var(--face-call);
  color: var(--ink-muted);
}

/* ---- weights ----------------------------------------------------------- */

.weigh {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--s3);
  padding: var(--s4);
  border: 1px solid var(--rule);
  background: var(--paper-sunk);
}

.weigh__row { display: flex; flex-direction: column; gap: var(--s1); }
.weigh__row--wide { flex: 1 1 12rem; }
.weigh label { font-size: 14px; font-weight: 500; }

.weigh input, .weigh select {
  min-height: var(--tap);
  padding: var(--s2);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  font: 400 16px/1.2 var(--face-ui);
}

.weigh input[type="number"] { font-family: var(--face-call); }
.weigh__hint { flex: 1 0 100%; margin: 0; font-size: 13px; color: var(--ink-muted); }

.table .wide { width: 45%; }

/* Two bars on one scale. A picture of the year is what the report wants, and it
   is cheaper drawn than fetched. */
.bar { display: block; height: 9px; min-width: 1px; margin: 2px 0; }
.bar--in  { background: var(--accent); }
.bar--out { background: var(--state-cards); }

.legend-inline { display: flex; align-items: center; gap: var(--s2); font-size: 13px; color: var(--ink-muted); }
.legend-inline .swatch { display: inline-block; width: 16px; height: 10px; border: 0; }
.swatch--in  { background: var(--accent); }
.swatch--out { background: var(--state-cards); }

/* The sorting column. Not shelves, and drawn so nobody looks for one in it --
   but the same width as the rest, because it is the same shelving. A plate here
   holds a category, so it has no state to hold and no colour to take. */
.shelf--sorting {
  background: var(--paper);
  color: var(--ink);
  cursor: default;
}

.sorting {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  margin: 0;
  padding-bottom: var(--s2);
  overflow: hidden;
  color: var(--ink-muted);
  font-size: 11px;
  text-align: center;
  background: repeating-linear-gradient(
    -45deg,
    transparent 0 6px,
    var(--rule-faint) 6px 7px
  );
}

.sheet--narrow { max-width: 34rem; }
.quiet { color: var(--ink-muted); font-size: 14px; }

.letter {
  margin: 0 0 var(--s4);
  padding: var(--s3);
  border: 1px solid var(--rule);
  background: var(--paper-sunk);
  font: 400 14px/1.5 var(--face-ui);
  white-space: pre-wrap;
}

.sheet textarea {
  width: 100%;
  padding: var(--s2);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  font: 400 16px/1.5 var(--face-ui);
}

.sheet label { display: block; margin-bottom: var(--s1); font-size: 14px; font-weight: 500; }

/* A field on a page looks like a field on the door. The weigh form lays its own
   out in a row, so it keeps its rules. */
.sheet form:not(.weigh) input[type="text"],
.sheet form:not(.weigh) input[type="email"],
.sheet form:not(.weigh) input[type="password"],
.sheet form:not(.weigh) input[type="number"] {
  display: block;
  width: 100%;
  min-height: var(--tap);
  margin-bottom: var(--s4);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  font: 400 16px/1.5 var(--face-ui);   /* never below 16px, or iOS zooms */
}

/* The button ends the form rather than sitting beside the last field. */
.sheet form:not(.weigh) > .button { display: flex; width: fit-content; }

.facts { display: grid; grid-template-columns: auto 1fr; gap: var(--s1) var(--s4); margin: 0 0 var(--s5); }
.facts dt { font-size: 14px; color: var(--ink-muted); }
.facts dd { margin: 0; }

.tick { display: flex; align-items: center; gap: var(--s2); margin-top: var(--s2); font-size: 13px; font-weight: 400; }
.tick input { width: 18px; height: 18px; }

.panel__done {
  margin: 0 0 var(--s3);
  padding: var(--s2) var(--s3);
  border-left: 4px solid var(--accent);
  background: var(--paper);
  font-size: 14px;
}

/* Prose, not interface: a readable measure and room between paragraphs. */
.sheet--prose { max-width: 40rem; }
.sheet--prose p, .sheet--prose ul, .sheet--prose dl { margin: 0 0 var(--s4); }
.sheet--prose li { margin-bottom: var(--s2); }
.sheet--prose h2 { margin-top: var(--s6); }

/* Somebody else's words, quoted exactly: set apart by a line, not by a box. */
.sheet--prose blockquote {
  margin: 0 0 var(--s4);
  padding: var(--s1) 0 var(--s1) var(--s4);
  border-left: 3px solid var(--rule);
}
.sheet--prose .lead { font-size: 18px; }
.sheet--prose .facts { grid-template-columns: auto 1fr; align-items: center; }

/* ---- the theme switch -------------------------------------------------- */

/* A button that cannot work should not be offered, and without script this one
   cannot. */
:root:not([data-js="on"]) .theme { display: none; }

/* Which of the three words shows. Decided here rather than by script, so it is
   right in the first frame instead of corrected after it. */
.theme [data-when] { display: none; }
:root[data-choice="system"] .theme [data-when="system"],
:root[data-choice="light"]  .theme [data-when="light"],
:root[data-choice="dark"]   .theme [data-when="dark"] { display: inline; }
